diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt
index e803f78ba91a..99903436b9d4 100644
--- a/src/audio/module_adapter/CMakeLists.txt
+++ b/src/audio/module_adapter/CMakeLists.txt
@@ -1,7 +1,11 @@
 # SPDX-License-Identifier: BSD-3-Clause
 
 
-add_local_sources(sof module_adapter.c module/generic.c)
+if(CONFIG_IPC_MAJOR_3)
+	add_local_sources(sof module_adapter.c module_adapter_ipc3.c module/generic.c)
+elseif(CONFIG_IPC_MAJOR_4)
+	add_local_sources(sof module_adapter.c module_adapter_ipc4.c module/generic.c)
+endif()
 
 if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC)
 	if(CONFIG_CADENCE_CODEC)
diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c
index e28541560403..5667130fb4b4 100644
--- a/src/audio/module_adapter/module_adapter.c
+++ b/src/audio/module_adapter/module_adapter.c
@@ -24,19 +24,6 @@
 
 LOG_MODULE_REGISTER(module_adapter, CONFIG_SOF_LOG_LEVEL);
 
-/*
- * helpers to determine processing type
- * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE
- */
-#define IS_PROCESSING_MODE_AUDIO_STREAM(mod) \
-		(!!((struct module_data *)&(mod)->priv)->ops->process_audio_stream)
-
-#define IS_PROCESSING_MODE_RAW_DATA(mod) \
-		(!!((struct module_data *)&(mod)->priv)->ops->process_raw_data)
-
-#define IS_PROCESSING_MODE_SINK_SOURCE(mod) \
-		(!!((struct module_data *)&(mod)->priv)->ops->process)
-
 /*
  * \brief Create a module adapter component.
  * \param[in] drv - component driver pointer.
@@ -90,62 +77,12 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv,
 	comp_set_drvdata(dev, mod);
 	list_init(&mod->sink_buffer_list);
 
-#if CONFIG_IPC_MAJOR_3
-	const unsigned char *data;
-	uint32_t size;
-
-	switch (config->type) {
-	case SOF_COMP_VOLUME:
-	{
-		const struct ipc_config_volume *ipc_volume = spec;
-
-		size = sizeof(*ipc_volume);
-		data = spec;
-		break;
-	}
-	case SOF_COMP_SRC:
-	{
-		const struct ipc_config_src *ipc_src = spec;
-
-		size = sizeof(*ipc_src);
-		data = spec;
-		break;
-	}
-	default:
-	{
-		const struct ipc_config_process *ipc_module_adapter = spec;
-
-		size = ipc_module_adapter->size;
-		data = ipc_module_adapter->data;
-		break;
-	}
-	}
-
-	/* Copy initial config */
-	if (size) {
-		ret = module_load_config(dev, data, size);
-		if (ret) {
-			comp_err(dev, "module_adapter_new() error %d: config loading has failed.",
-				 ret);
-			goto err;
-		}
-		dst->init_data = dst->data;
-	} else {
+	ret = module_adapter_init_data(dev, dst, config, spec);
+	if (ret) {
+		comp_err(dev, "module_adapter_new() %d: module init data failed",
+			 ret);
 		goto err;
 	}
-#else
-	if (drv->type == SOF_COMP_MODULE_ADAPTER) {
-		const struct ipc_config_process *ipc_module_adapter = spec;
-
-		dst->init_data = ipc_module_adapter->data;
-		dst->size = ipc_module_adapter->size;
-		dst->avail = true;
-
-		memcpy(&dst->base_cfg, ipc_module_adapter->data, sizeof(dst->base_cfg));
-	} else {
-		dst->init_data = spec;
-	}
-#endif
 
 	/* Modules must modify them if they support more than 1 source/sink */
 	mod->max_sources = 1;
@@ -159,9 +96,7 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv,
 		goto err;
 	}
 
-#if CONFIG_IPC_MAJOR_4
-	dst->init_data = NULL;
-#endif
+	module_adapter_reset_data(dst);
 	dev->state = COMP_STATE_READY;
 
 	comp_dbg(dev, "module_adapter_new() done");
@@ -325,18 +260,7 @@ int module_adapter_prepare(struct comp_dev *dev)
 		return -EINVAL;
 	}
 
-#if CONFIG_IPC_MAJOR_3
-	/* Check if audio stream client has only one source and one sink buffer to use a
-	 * simplified copy function.
-	 */
-	if (IS_PROCESSING_MODE_AUDIO_STREAM(mod) && mod->num_input_buffers == 1 &&
-	    mod->num_output_buffers == 1) {
-		mod->source_comp_buffer = list_first_item(&dev->bsource_list,
-							  struct comp_buffer, sink_list);
-		mod->sink_comp_buffer = sink;
-		mod->stream_copy_single_to_single = true;
-	}
-#endif
+	module_adapter_check_data(mod, dev, sink);
 
 	/* allocate memory for input buffers */
 	if (mod->max_sources) {
@@ -551,10 +475,7 @@ int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *pa
 			return ret;
 	}
 
-#if CONFIG_IPC_MAJOR_4
-	ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params);
-	ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, mod->stream_params);
-#endif
+	module_adapter_set_params(mod, params);
 	return 0;
 }
 
@@ -736,7 +657,7 @@ static void module_adapter_process_output(struct comp_dev *dev)
 	mod->total_data_produced += mod->output_buffers[0].size;
 }
 
-static uint32_t
+uint32_t
 module_single_sink_setup(struct comp_dev *dev,
 			 struct comp_buffer __sparse_cache **source_c,
 			 struct comp_buffer __sparse_cache **sinks_c)
@@ -777,7 +698,7 @@ module_single_sink_setup(struct comp_dev *dev,
 	return num_input_buffers;
 }
 
-static uint32_t
+uint32_t
 module_single_source_setup(struct comp_dev *dev,
 			   struct comp_buffer __sparse_cache **source_c,
 			   struct comp_buffer __sparse_cache **sinks_c)
@@ -820,7 +741,7 @@ module_single_source_setup(struct comp_dev *dev,
 	return num_output_buffers;
 }
 
-static int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev)
+int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev)
 {
 	struct processing_module *mod = comp_get_drvdata(dev);
 	struct comp_buffer __sparse_cache *source_c;
@@ -869,144 +790,6 @@ static int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev)
 	return ret;
 }
 
-static int module_adapter_audio_stream_type_copy(struct comp_dev *dev)
-{
-	struct comp_buffer __sparse_cache *source_c[PLATFORM_MAX_STREAMS];
-	struct comp_buffer __sparse_cache *sinks_c[PLATFORM_MAX_STREAMS];
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct list_item *blist;
-	uint32_t num_input_buffers, num_output_buffers;
-	int ret, i = 0;
-
-	/* handle special case of HOST/DAI type components */
-	if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI)
-#if CONFIG_IPC_MAJOR_3
-		return module_process_legacy(mod, NULL, 0, NULL, 0);
-#else
-		return module_process_stream(mod, NULL, 0, NULL, 0);
-#endif
-
-	if (mod->stream_copy_single_to_single)
-		return module_adapter_audio_stream_copy_1to1(dev);
-
-	/* acquire all sink and source buffers */
-	list_for_item(blist, &dev->bsink_list) {
-		struct comp_buffer *sink;
-
-		sink = container_of(blist, struct comp_buffer, source_list);
-		sinks_c[i++] = buffer_acquire(sink);
-	}
-	num_output_buffers = i;
-	if (num_output_buffers > mod->max_sinks) {
-		comp_err(dev, "Invalid number of sinks %d\n", num_output_buffers);
-		return -EINVAL;
-	}
-
-	i = 0;
-	list_for_item(blist, &dev->bsource_list) {
-		struct comp_buffer *source;
-
-		source = container_of(blist, struct comp_buffer, sink_list);
-		source_c[i++] = buffer_acquire(source);
-	}
-	num_input_buffers = i;
-	if (num_input_buffers > mod->max_sources) {
-		comp_err(dev, "Invalid number of sinks %d\n", num_input_buffers);
-		return -EINVAL;
-	}
-
-	/* setup active input/output buffers for processing */
-	if (num_output_buffers == 1) {
-		module_single_sink_setup(dev, source_c, sinks_c);
-		if (sinks_c[0]->sink->state != dev->state) {
-			num_output_buffers = 0;
-			buffer_release(sinks_c[0]);
-		}
-	} else if (num_input_buffers == 1) {
-		module_single_source_setup(dev, source_c, sinks_c);
-		if (source_c[0]->source->state != dev->state) {
-			num_input_buffers = 0;
-			buffer_release(source_c[0]);
-		}
-	} else {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = module_process_legacy(mod, mod->input_buffers, num_input_buffers,
-				    mod->output_buffers, num_output_buffers);
-	if (ret) {
-		if (ret != -ENOSPC && ret != -ENODATA) {
-			comp_err(dev,
-				 "module_adapter_audio_stream_type_copy() failed with error: %x",
-				 ret);
-			goto out;
-		}
-
-		ret = 0;
-	}
-
-	/* consume from all active input buffers */
-	for (i = 0; i < num_input_buffers; i++) {
-		struct comp_buffer __sparse_cache *src_c;
-
-		src_c = attr_container_of(mod->input_buffers[i].data,
-					  struct comp_buffer __sparse_cache,
-					  stream, __sparse_cache);
-		if (mod->input_buffers[i].consumed)
-			audio_stream_consume(&src_c->stream, mod->input_buffers[i].consumed);
-	}
-
-	/* compute data consumed based on pin 0 since it is processed with base config
-	 * which is set for pin 0
-	 */
-	mod->total_data_consumed += mod->input_buffers[0].consumed;
-
-	/* release all source buffers */
-	for (i = 0; i < num_input_buffers; i++) {
-		buffer_release(source_c[i]);
-		mod->input_buffers[i].size = 0;
-		mod->input_buffers[i].consumed = 0;
-	}
-
-	/* produce data into all active output buffers */
-	for (i = 0; i < num_output_buffers; i++) {
-		struct comp_buffer __sparse_cache *sink_c;
-
-		sink_c = attr_container_of(mod->output_buffers[i].data,
-					   struct comp_buffer __sparse_cache,
-					   stream, __sparse_cache);
-
-		if (!mod->skip_sink_buffer_writeback)
-			buffer_stream_writeback(sink_c, mod->output_buffers[i].size);
-		if (mod->output_buffers[i].size)
-			comp_update_buffer_produce(sink_c, mod->output_buffers[i].size);
-	}
-
-	mod->total_data_produced += mod->output_buffers[0].size;
-
-	/* release all sink buffers */
-	for (i = 0; i < num_output_buffers; i++) {
-		buffer_release(sinks_c[i]);
-		mod->output_buffers[i].size = 0;
-	}
-
-	return 0;
-out:
-	for (i = 0; i < num_output_buffers; i++) {
-		buffer_release(sinks_c[i]);
-		mod->output_buffers[i].size = 0;
-	}
-
-	for (i = 0; i < num_input_buffers; i++) {
-		buffer_release(source_c[i]);
-		mod->input_buffers[i].size = 0;
-		mod->input_buffers[i].consumed = 0;
-	}
-
-	return ret;
-}
-
 static int module_adapter_sink_source_copy(struct comp_dev *dev)
 {
 	struct comp_buffer __sparse_cache *source_buffers_c[PLATFORM_MAX_STREAMS];
@@ -1316,34 +1099,6 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s
 	return ret;
 }
 
-#if CONFIG_IPC_MAJOR_3
-static int module_source_status_count(struct comp_dev *dev, uint32_t status)
-{
-	struct list_item *blist;
-	int count = 0;
-
-	/* count source with state == status */
-	list_for_item(blist, &dev->bsource_list) {
-		/*
-		 * FIXME: this is racy, state can be changed by another core.
-		 * This is implicitly protected by serialised IPCs. Even when
-		 * IPCs are processed in the pipeline thread, the next IPC will
-		 * not be sent until the thread has processed and replied to the
-		 * current one.
-		 */
-		struct comp_buffer *source = container_of(blist, struct comp_buffer,
-							  sink_list);
-		struct comp_buffer __sparse_cache *source_c = buffer_acquire(source);
-
-		if (source_c->source && source_c->source->state == status)
-			count++;
-		buffer_release(source_c);
-	}
-
-	return count;
-}
-#endif
-
 int module_adapter_trigger(struct comp_dev *dev, int cmd)
 {
 	struct processing_module *mod = comp_get_drvdata(dev);
@@ -1366,28 +1121,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd)
 		return PPL_STATUS_PATH_STOP;
 	}
 
-#if CONFIG_IPC_MAJOR_3
-	if (mod->num_input_buffers > 1) {
-		bool sources_active;
-		int ret;
-
-		sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) ||
-				 module_source_status_count(dev, COMP_STATE_PAUSED);
-
-		/* don't stop/start module if one of the sources is active/paused */
-		if ((cmd == COMP_TRIGGER_STOP || cmd == COMP_TRIGGER_PRE_START) && sources_active) {
-			dev->state = COMP_STATE_ACTIVE;
-			return PPL_STATUS_PATH_STOP;
-		}
-
-		ret = comp_set_state(dev, cmd);
-		if (ret == COMP_STATUS_STATE_ALREADY_SET)
-			return PPL_STATUS_PATH_STOP;
-
-		return ret;
-	}
-#endif
-	return comp_set_state(dev, cmd);
+	return module_adapter_set_state(mod, dev, cmd);
 }
 
 int module_adapter_reset(struct comp_dev *dev)
@@ -1583,254 +1317,3 @@ int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd)
 
 	return -EOPNOTSUPP;
 }
-
-#if CONFIG_IPC_MAJOR_4
-int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
-			    bool last_block, uint32_t data_offset_size, const char *data)
-{
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct module_data *md = &mod->priv;
-	enum module_cfg_fragment_position pos;
-	size_t fragment_size;
-
-	/* set fragment position */
-	pos = first_last_block_to_frag_pos(first_block, last_block);
-
-	switch (pos) {
-	case MODULE_CFG_FRAGMENT_SINGLE:
-		fragment_size = data_offset_size;
-		break;
-	case MODULE_CFG_FRAGMENT_MIDDLE:
-		fragment_size = MAILBOX_DSPBOX_SIZE;
-		break;
-	case MODULE_CFG_FRAGMENT_FIRST:
-		md->new_cfg_size = data_offset_size;
-		fragment_size = MAILBOX_DSPBOX_SIZE;
-		break;
-	case MODULE_CFG_FRAGMENT_LAST:
-		fragment_size = md->new_cfg_size - data_offset_size;
-		break;
-	default:
-		comp_err(dev, "module_set_large_config(): invalid fragment position");
-		return -EINVAL;
-	}
-
-	if (md->ops->set_configuration)
-		return md->ops->set_configuration(mod, param_id, pos, data_offset_size,
-						  (const uint8_t *)data,
-						  fragment_size, NULL, 0);
-	return 0;
-}
-
-int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
-			    bool last_block, uint32_t *data_offset_size, char *data)
-{
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct module_data *md = &mod->priv;
-	size_t fragment_size;
-
-	/* set fragment size */
-	if (first_block) {
-		if (last_block)
-			fragment_size = md->cfg.size;
-		else
-			fragment_size = SOF_IPC_MSG_MAX_SIZE;
-	} else {
-		if (!last_block)
-			fragment_size = SOF_IPC_MSG_MAX_SIZE;
-		else
-			fragment_size = md->cfg.size - *data_offset_size;
-	}
-
-	if (md->ops->get_configuration)
-		return md->ops->get_configuration(mod, param_id, data_offset_size,
-						  (uint8_t *)data, fragment_size);
-	return 0;
-}
-
-int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value)
-{
-	struct processing_module *mod = comp_get_drvdata(dev);
-
-	switch (type) {
-	case COMP_ATTR_BASE_CONFIG:
-		memcpy_s(value, sizeof(struct ipc4_base_module_cfg),
-			 &mod->priv.cfg.base_cfg, sizeof(mod->priv.cfg.base_cfg));
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static bool module_adapter_multi_sink_source_check(struct comp_dev *dev)
-{
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct list_item *blist;
-	int num_sources = 0;
-	int num_sinks = 0;
-
-	list_for_item(blist, &dev->bsource_list)
-		num_sources++;
-
-	list_for_item(blist, &dev->bsink_list)
-		num_sinks++;
-
-	comp_dbg(dev, "num_sources=%d num_sinks=%d", num_sources, num_sinks);
-
-	if (num_sources != 1 || num_sinks != 1)
-		return true;
-
-	/* re-assign the source/sink modules */
-	mod->sink_comp_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);
-	mod->source_comp_buffer = list_first_item(&dev->bsource_list,
-						  struct comp_buffer, sink_list);
-
-	return false;
-}
-
-int module_adapter_bind(struct comp_dev *dev, void *data)
-{
-	struct module_source_info __sparse_cache *mod_source_info;
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct ipc4_module_bind_unbind *bu;
-	struct comp_dev *source_dev;
-	int source_index;
-	int src_id;
-	int ret;
-
-	ret = module_bind(mod, data);
-	if (ret < 0)
-		return ret;
-
-	bu = (struct ipc4_module_bind_unbind *)data;
-	src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id);
-
-	mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev);
-
-	/* nothing to do if this module is the source during bind */
-	if (dev->ipc_config.id == src_id)
-		return 0;
-
-	source_dev = ipc4_get_comp_dev(src_id);
-	if (!source_dev) {
-		comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id);
-		return -EINVAL;
-	}
-
-	mod_source_info = module_source_info_acquire(mod->source_info);
-
-	source_index = find_module_source_index(mod_source_info, source_dev);
-	/*
-	 * this should never happen as source_info should have been already cleared in
-	 * module_adapter_unbind()
-	 */
-	if (source_index >= 0)
-		mod_source_info->sources[source_index] = NULL;
-
-	/* find an empty slot in the source_info array */
-	source_index = find_module_source_index(mod_source_info, NULL);
-	if (source_index < 0) {
-		/* no free slot in module source_info array */
-		comp_err(dev, "Too many inputs!");
-		module_source_info_release(mod_source_info);
-		return -ENOMEM;
-	}
-
-	/* set the source dev pointer */
-	mod_source_info->sources[source_index] = source_dev;
-
-	module_source_info_release(mod_source_info);
-
-	return 0;
-}
-
-int module_adapter_unbind(struct comp_dev *dev, void *data)
-{
-	struct module_source_info __sparse_cache *mod_source_info;
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct ipc4_module_bind_unbind *bu;
-	struct comp_dev *source_dev;
-	int source_index;
-	int src_id;
-	int ret;
-
-	ret = module_unbind(mod, data);
-	if (ret < 0)
-		return ret;
-
-	bu = (struct ipc4_module_bind_unbind *)data;
-	src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id);
-
-	mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev);
-
-	/* nothing to do if this module is the source during unbind */
-	if (dev->ipc_config.id == src_id)
-		return 0;
-
-	source_dev = ipc4_get_comp_dev(src_id);
-	if (!source_dev) {
-		comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id);
-		return -EINVAL;
-	}
-
-	mod_source_info = module_source_info_acquire(mod->source_info);
-
-	/* find the index of the source in the sources array and clear it */
-	source_index = find_module_source_index(mod_source_info, source_dev);
-	if (source_index >= 0)
-		mod_source_info->sources[source_index] = NULL;
-
-	module_source_info_release(mod_source_info);
-
-	return 0;
-}
-
-uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev,
-						 uint32_t stream_no, bool input)
-{
-	struct processing_module *mod = comp_get_drvdata(dev);
-	struct module_data *md = &mod->priv;
-
-	if (md->ops->endpoint_ops && md->ops->endpoint_ops->get_total_data_processed)
-		return md->ops->endpoint_ops->get_total_data_processed(dev, stream_no, input);
-
-	if (input)
-		return mod->total_data_produced;
-	else
-		return mod->total_data_consumed;
-}
-#else
-int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value)
-{
-	return -EINVAL;
-}
-int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
-			    bool last_block, uint32_t data_offset, const char *data)
-{
-	return 0;
-}
-
-int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
-			    bool last_block, uint32_t *data_offset, char *data)
-{
-	return 0;
-}
-
-int module_adapter_bind(struct comp_dev *dev, void *data)
-{
-	return 0;
-}
-
-int module_adapter_unbind(struct comp_dev *dev, void *data)
-{
-	return 0;
-}
-
-uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev,
-						 uint32_t stream_no, bool input)
-{
-	return 0;
-}
-#endif
diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c
new file mode 100644
index 000000000000..09df939a6bc9
--- /dev/null
+++ b/src/audio/module_adapter/module_adapter_ipc3.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+//
+// Author: Baofeng Tian <baofeng.tian@intel.com>
+
+/**
+ * \file
+ * \brief Module Adapter ipc3: module adapter ipc3 specific code
+ * \author Baofeng Tian <baofeng.tian@intel.com>
+ */
+
+#include <sof/audio/buffer.h>
+#include <sof/audio/component.h>
+#include <sof/audio/ipc-config.h>
+#include <sof/audio/module_adapter/module/generic.h>
+#include <sof/audio/pipeline.h>
+#include <sof/common.h>
+#include <sof/platform.h>
+#include <sof/ut.h>
+#include <rtos/interrupt.h>
+#include <limits.h>
+#include <stdint.h>
+
+LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL);
+
+/*
+ * \module adapter data initialize.
+ * \param[in] dev - device.
+ * \param[in] config - component ipc descriptor pointer.
+ * \param[in] dst - module adapter config data.
+ * \param[in] spec - passdowned data from driver.
+ *
+ * \return: 0 - no error; < 0, error happened.
+ */
+int module_adapter_init_data(struct comp_dev *dev,
+			     struct module_config *dst,
+			     const struct comp_ipc_config *config,
+			     const void *spec)
+{
+	int ret;
+
+	const unsigned char *data;
+	uint32_t size;
+
+	switch (config->type) {
+	case SOF_COMP_VOLUME:
+	{
+		const struct ipc_config_volume *ipc_volume = spec;
+
+		size = sizeof(*ipc_volume);
+		data = spec;
+		break;
+	}
+	case SOF_COMP_SRC:
+	{
+		const struct ipc_config_src *ipc_src = spec;
+
+		size = sizeof(*ipc_src);
+		data = spec;
+		break;
+	}
+	default:
+	{
+		const struct ipc_config_process *ipc_module_adapter = spec;
+
+		size = ipc_module_adapter->size;
+		data = ipc_module_adapter->data;
+		break;
+	}
+	}
+
+	/* Copy initial config */
+	if (size) {
+		ret = module_load_config(dev, data, size);
+		if (ret < 0) {
+			comp_err(dev, "module_adapter_new() error %d: config loading has failed.",
+				 ret);
+			return ret;
+		}
+		dst->init_data = dst->data;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void module_adapter_reset_data(struct module_config *dst)
+{
+}
+
+void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev,
+			       struct comp_buffer *sink)
+{
+	/* Check if audio stream client has only one source and one sink buffer to use a
+	 * simplified copy function.
+	 */
+	if (IS_PROCESSING_MODE_AUDIO_STREAM(mod) && mod->num_input_buffers == 1 &&
+	    mod->num_output_buffers == 1) {
+		mod->source_comp_buffer = list_first_item(&dev->bsource_list,
+							  struct comp_buffer, sink_list);
+		mod->sink_comp_buffer = sink;
+		mod->stream_copy_single_to_single = true;
+	}
+}
+
+void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params)
+{
+}
+
+int module_adapter_audio_stream_type_copy(struct comp_dev *dev)
+{
+	struct comp_buffer __sparse_cache *source_c[PLATFORM_MAX_STREAMS];
+	struct comp_buffer __sparse_cache *sinks_c[PLATFORM_MAX_STREAMS];
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct list_item *blist;
+	uint32_t num_input_buffers, num_output_buffers;
+	int ret, i = 0;
+
+	/* handle special case of HOST/DAI type components */
+	if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI)
+		return module_process_legacy(mod, NULL, 0, NULL, 0);
+
+	if (mod->stream_copy_single_to_single)
+		return module_adapter_audio_stream_copy_1to1(dev);
+
+	/* acquire all sink and source buffers */
+	list_for_item(blist, &dev->bsink_list) {
+		struct comp_buffer *sink;
+
+		sink = container_of(blist, struct comp_buffer, source_list);
+		sinks_c[i++] = buffer_acquire(sink);
+	}
+	num_output_buffers = i;
+	if (num_output_buffers > mod->max_sinks) {
+		comp_err(dev, "Invalid number of sinks %d\n", num_output_buffers);
+		return -EINVAL;
+	}
+
+	i = 0;
+	list_for_item(blist, &dev->bsource_list) {
+		struct comp_buffer *source;
+
+		source = container_of(blist, struct comp_buffer, sink_list);
+		source_c[i++] = buffer_acquire(source);
+	}
+	num_input_buffers = i;
+	if (num_input_buffers > mod->max_sources) {
+		comp_err(dev, "Invalid number of sinks %d\n", num_input_buffers);
+		return -EINVAL;
+	}
+
+	/* setup active input/output buffers for processing */
+	if (num_output_buffers == 1) {
+		module_single_sink_setup(dev, source_c, sinks_c);
+		if (sinks_c[0]->sink->state != dev->state) {
+			num_output_buffers = 0;
+			buffer_release(sinks_c[0]);
+		}
+	} else if (num_input_buffers == 1) {
+		module_single_source_setup(dev, source_c, sinks_c);
+		if (source_c[0]->source->state != dev->state) {
+			num_input_buffers = 0;
+			buffer_release(source_c[0]);
+		}
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = module_process_legacy(mod, mod->input_buffers, num_input_buffers,
+				    mod->output_buffers, num_output_buffers);
+	if (ret) {
+		if (ret != -ENOSPC && ret != -ENODATA) {
+			comp_err(dev,
+				 "module_adapter_audio_stream_type_copy() failed with error: %x",
+				 ret);
+			goto out;
+		}
+
+		ret = 0;
+	}
+
+	/* consume from all active input buffers */
+	for (i = 0; i < num_input_buffers; i++) {
+		struct comp_buffer __sparse_cache *src_c;
+
+		src_c = attr_container_of(mod->input_buffers[i].data,
+					  struct comp_buffer __sparse_cache,
+					  stream, __sparse_cache);
+		if (mod->input_buffers[i].consumed)
+			audio_stream_consume(&src_c->stream, mod->input_buffers[i].consumed);
+	}
+
+	/* compute data consumed based on pin 0 since it is processed with base config
+	 * which is set for pin 0
+	 */
+	mod->total_data_consumed += mod->input_buffers[0].consumed;
+
+	/* release all source buffers */
+	for (i = 0; i < num_input_buffers; i++) {
+		buffer_release(source_c[i]);
+		mod->input_buffers[i].size = 0;
+		mod->input_buffers[i].consumed = 0;
+	}
+
+	/* produce data into all active output buffers */
+	for (i = 0; i < num_output_buffers; i++) {
+		struct comp_buffer __sparse_cache *sink_c;
+
+		sink_c = attr_container_of(mod->output_buffers[i].data,
+					   struct comp_buffer __sparse_cache,
+					   stream, __sparse_cache);
+
+		if (!mod->skip_sink_buffer_writeback)
+			buffer_stream_writeback(sink_c, mod->output_buffers[i].size);
+		if (mod->output_buffers[i].size)
+			comp_update_buffer_produce(sink_c, mod->output_buffers[i].size);
+	}
+
+	mod->total_data_produced += mod->output_buffers[0].size;
+
+	/* release all sink buffers */
+	for (i = 0; i < num_output_buffers; i++) {
+		buffer_release(sinks_c[i]);
+		mod->output_buffers[i].size = 0;
+	}
+
+	return 0;
+out:
+	for (i = 0; i < num_output_buffers; i++) {
+		buffer_release(sinks_c[i]);
+		mod->output_buffers[i].size = 0;
+	}
+
+	for (i = 0; i < num_input_buffers; i++) {
+		buffer_release(source_c[i]);
+		mod->input_buffers[i].size = 0;
+		mod->input_buffers[i].consumed = 0;
+	}
+
+	return ret;
+}
+
+static int module_source_status_count(struct comp_dev *dev, uint32_t status)
+{
+	struct list_item *blist;
+	int count = 0;
+
+	/* count source with state == status */
+	list_for_item(blist, &dev->bsource_list) {
+		/*
+		 * FIXME: this is racy, state can be changed by another core.
+		 * This is implicitly protected by serialised IPCs. Even when
+		 * IPCs are processed in the pipeline thread, the next IPC will
+		 * not be sent until the thread has processed and replied to the
+		 * current one.
+		 */
+		struct comp_buffer *source = container_of(blist, struct comp_buffer,
+							  sink_list);
+		struct comp_buffer __sparse_cache *source_c = buffer_acquire(source);
+
+		if (source_c->source && source_c->source->state == status)
+			count++;
+		buffer_release(source_c);
+	}
+
+	return count;
+}
+
+int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev,
+			     int cmd)
+{
+	if (mod->num_input_buffers > 1) {
+		bool sources_active;
+		int ret;
+
+		sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) ||
+				 module_source_status_count(dev, COMP_STATE_PAUSED);
+
+		/* don't stop/start module if one of the sources is active/paused */
+		if ((cmd == COMP_TRIGGER_STOP || cmd == COMP_TRIGGER_PRE_START) && sources_active) {
+			dev->state = COMP_STATE_ACTIVE;
+			return PPL_STATUS_PATH_STOP;
+		}
+
+		ret = comp_set_state(dev, cmd);
+		if (ret == COMP_STATUS_STATE_ALREADY_SET)
+			return PPL_STATUS_PATH_STOP;
+
+		return ret;
+	}
+
+	return comp_set_state(dev, cmd);
+}
+
+int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value)
+{
+	return -EINVAL;
+}
+
+int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
+			    bool last_block, uint32_t data_offset, const char *data)
+{
+	return 0;
+}
+
+int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
+			    bool last_block, uint32_t *data_offset, char *data)
+{
+	return 0;
+}
+
+int module_adapter_bind(struct comp_dev *dev, void *data)
+{
+	return 0;
+}
+
+int module_adapter_unbind(struct comp_dev *dev, void *data)
+{
+	return 0;
+}
+
+uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev,
+						 uint32_t stream_no, bool input)
+{
+	return 0;
+}
+
diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c
new file mode 100644
index 000000000000..4010403e170c
--- /dev/null
+++ b/src/audio/module_adapter/module_adapter_ipc4.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+//
+// Author: Baofeng Tian <baofeng.tian@intel.com>
+
+/**
+ * \file
+ * \brief Module Adapter ipc4: module adapter ipc4 specific code
+ * \author Baofeng Tian <baofeng.tian@intel.com>
+ */
+
+#include <sof/audio/buffer.h>
+#include <sof/audio/component.h>
+#include <sof/audio/ipc-config.h>
+#include <sof/audio/module_adapter/module/generic.h>
+#include <sof/audio/pipeline.h>
+#include <sof/common.h>
+#include <sof/platform.h>
+#include <sof/ut.h>
+#include <rtos/interrupt.h>
+#include <limits.h>
+#include <stdint.h>
+
+LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL);
+
+/*
+ * \module adapter data initialize.
+ * \param[in] dev - device.
+ * \param[in] config - component ipc descriptor pointer.
+ * \param[in] dst - module adapter config data.
+ * \param[in] spec - passdowned data from driver.
+ *
+ * \return: 0 - no error; < 0, error happened.
+ */
+int module_adapter_init_data(struct comp_dev *dev,
+			     struct module_config *dst,
+			     const struct comp_ipc_config *config,
+			     const void *spec)
+{
+	if (dev->drv->type == SOF_COMP_MODULE_ADAPTER) {
+		const struct ipc_config_process *ipc_module_adapter = spec;
+
+		dst->init_data = ipc_module_adapter->data;
+		dst->size = ipc_module_adapter->size;
+		dst->avail = true;
+
+		memcpy_s(&dst->base_cfg,  sizeof(dst->base_cfg), ipc_module_adapter->data,
+			 sizeof(dst->base_cfg));
+	} else {
+		dst->init_data = spec;
+	}
+
+	return 0;
+}
+
+void module_adapter_reset_data(struct module_config *dst)
+{
+	dst->init_data = NULL;
+}
+
+void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev,
+			       struct comp_buffer *sink)
+{
+}
+
+void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params)
+{
+	ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params);
+	ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, mod->stream_params);
+}
+
+int module_adapter_audio_stream_type_copy(struct comp_dev *dev)
+{
+	struct comp_buffer __sparse_cache *source_c[PLATFORM_MAX_STREAMS];
+	struct comp_buffer __sparse_cache *sinks_c[PLATFORM_MAX_STREAMS];
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct list_item *blist;
+	uint32_t num_input_buffers, num_output_buffers;
+	int ret, i = 0;
+
+	/* handle special case of HOST/DAI type components */
+	if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI)
+		return module_process_stream(mod, NULL, 0, NULL, 0);
+
+	if (mod->stream_copy_single_to_single)
+		return module_adapter_audio_stream_copy_1to1(dev);
+
+	/* acquire all sink and source buffers */
+	list_for_item(blist, &dev->bsink_list) {
+		struct comp_buffer *sink;
+
+		sink = container_of(blist, struct comp_buffer, source_list);
+		sinks_c[i++] = buffer_acquire(sink);
+	}
+	num_output_buffers = i;
+	if (num_output_buffers > mod->max_sinks) {
+		comp_err(dev, "Invalid number of sinks %d\n", num_output_buffers);
+		return -EINVAL;
+	}
+
+	i = 0;
+	list_for_item(blist, &dev->bsource_list) {
+		struct comp_buffer *source;
+
+		source = container_of(blist, struct comp_buffer, sink_list);
+		source_c[i++] = buffer_acquire(source);
+	}
+	num_input_buffers = i;
+	if (num_input_buffers > mod->max_sources) {
+		comp_err(dev, "Invalid number of sinks %d\n", num_input_buffers);
+		return -EINVAL;
+	}
+
+	/* setup active input/output buffers for processing */
+	if (num_output_buffers == 1) {
+		module_single_sink_setup(dev, source_c, sinks_c);
+		if (sinks_c[0]->sink->state != dev->state) {
+			num_output_buffers = 0;
+			buffer_release(sinks_c[0]);
+		}
+	} else if (num_input_buffers == 1) {
+		module_single_source_setup(dev, source_c, sinks_c);
+		if (source_c[0]->source->state != dev->state) {
+			num_input_buffers = 0;
+			buffer_release(source_c[0]);
+		}
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = module_process_legacy(mod, mod->input_buffers, num_input_buffers,
+				    mod->output_buffers, num_output_buffers);
+	if (ret) {
+		if (ret != -ENOSPC && ret != -ENODATA) {
+			comp_err(dev,
+				 "module_adapter_audio_stream_type_copy() failed with error: %x",
+				 ret);
+			goto out;
+		}
+
+		ret = 0;
+	}
+
+	/* consume from all active input buffers */
+	for (i = 0; i < num_input_buffers; i++) {
+		struct comp_buffer __sparse_cache *src_c;
+
+		src_c = attr_container_of(mod->input_buffers[i].data,
+					  struct comp_buffer __sparse_cache,
+					  stream, __sparse_cache);
+		if (mod->input_buffers[i].consumed)
+			audio_stream_consume(&src_c->stream, mod->input_buffers[i].consumed);
+	}
+
+	/* compute data consumed based on pin 0 since it is processed with base config
+	 * which is set for pin 0
+	 */
+	mod->total_data_consumed += mod->input_buffers[0].consumed;
+
+	/* release all source buffers */
+	for (i = 0; i < num_input_buffers; i++) {
+		buffer_release(source_c[i]);
+		mod->input_buffers[i].size = 0;
+		mod->input_buffers[i].consumed = 0;
+	}
+
+	/* produce data into all active output buffers */
+	for (i = 0; i < num_output_buffers; i++) {
+		struct comp_buffer __sparse_cache *sink_c;
+
+		sink_c = attr_container_of(mod->output_buffers[i].data,
+					   struct comp_buffer __sparse_cache,
+					   stream, __sparse_cache);
+
+		if (!mod->skip_sink_buffer_writeback)
+			buffer_stream_writeback(sink_c, mod->output_buffers[i].size);
+		if (mod->output_buffers[i].size)
+			comp_update_buffer_produce(sink_c, mod->output_buffers[i].size);
+	}
+
+	mod->total_data_produced += mod->output_buffers[0].size;
+
+	/* release all sink buffers */
+	for (i = 0; i < num_output_buffers; i++) {
+		buffer_release(sinks_c[i]);
+		mod->output_buffers[i].size = 0;
+	}
+
+	return 0;
+out:
+	for (i = 0; i < num_output_buffers; i++) {
+		buffer_release(sinks_c[i]);
+		mod->output_buffers[i].size = 0;
+	}
+
+	for (i = 0; i < num_input_buffers; i++) {
+		buffer_release(source_c[i]);
+		mod->input_buffers[i].size = 0;
+		mod->input_buffers[i].consumed = 0;
+	}
+
+	return ret;
+}
+
+int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev,
+			     int cmd)
+{
+	return comp_set_state(dev, cmd);
+}
+
+int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
+			    bool last_block, uint32_t data_offset_size, const char *data)
+{
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct module_data *md = &mod->priv;
+	enum module_cfg_fragment_position pos;
+	size_t fragment_size;
+
+	/* set fragment position */
+	pos = first_last_block_to_frag_pos(first_block, last_block);
+
+	switch (pos) {
+	case MODULE_CFG_FRAGMENT_SINGLE:
+		fragment_size = data_offset_size;
+		break;
+	case MODULE_CFG_FRAGMENT_MIDDLE:
+		fragment_size = MAILBOX_DSPBOX_SIZE;
+		break;
+	case MODULE_CFG_FRAGMENT_FIRST:
+		md->new_cfg_size = data_offset_size;
+		fragment_size = MAILBOX_DSPBOX_SIZE;
+		break;
+	case MODULE_CFG_FRAGMENT_LAST:
+		fragment_size = md->new_cfg_size - data_offset_size;
+		break;
+	default:
+		comp_err(dev, "module_set_large_config(): invalid fragment position");
+		return -EINVAL;
+	}
+
+	if (md->ops->set_configuration)
+		return md->ops->set_configuration(mod, param_id, pos, data_offset_size,
+						  (const uint8_t *)data,
+						  fragment_size, NULL, 0);
+	return 0;
+}
+
+int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block,
+			    bool last_block, uint32_t *data_offset_size, char *data)
+{
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct module_data *md = &mod->priv;
+	size_t fragment_size;
+
+	/* set fragment size */
+	if (first_block) {
+		if (last_block)
+			fragment_size = md->cfg.size;
+		else
+			fragment_size = SOF_IPC_MSG_MAX_SIZE;
+	} else {
+		if (!last_block)
+			fragment_size = SOF_IPC_MSG_MAX_SIZE;
+		else
+			fragment_size = md->cfg.size - *data_offset_size;
+	}
+
+	if (md->ops->get_configuration)
+		return md->ops->get_configuration(mod, param_id, data_offset_size,
+						  (uint8_t *)data, fragment_size);
+	return 0;
+}
+
+int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value)
+{
+	struct processing_module *mod = comp_get_drvdata(dev);
+
+	switch (type) {
+	case COMP_ATTR_BASE_CONFIG:
+		memcpy_s(value, sizeof(struct ipc4_base_module_cfg),
+			 &mod->priv.cfg.base_cfg, sizeof(mod->priv.cfg.base_cfg));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static bool module_adapter_multi_sink_source_check(struct comp_dev *dev)
+{
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct list_item *blist;
+	int num_sources = 0;
+	int num_sinks = 0;
+
+	list_for_item(blist, &dev->bsource_list)
+		num_sources++;
+
+	list_for_item(blist, &dev->bsink_list)
+		num_sinks++;
+
+	comp_dbg(dev, "num_sources=%d num_sinks=%d", num_sources, num_sinks);
+
+	if (num_sources != 1 || num_sinks != 1)
+		return true;
+
+	/* re-assign the source/sink modules */
+	mod->sink_comp_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);
+	mod->source_comp_buffer = list_first_item(&dev->bsource_list,
+						  struct comp_buffer, sink_list);
+
+	return false;
+}
+
+int module_adapter_bind(struct comp_dev *dev, void *data)
+{
+	struct module_source_info __sparse_cache *mod_source_info;
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct ipc4_module_bind_unbind *bu;
+	struct comp_dev *source_dev;
+	int source_index;
+	int src_id;
+	int ret;
+
+	ret = module_bind(mod, data);
+	if (ret < 0)
+		return ret;
+
+	bu = (struct ipc4_module_bind_unbind *)data;
+	src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id);
+
+	mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev);
+
+	/* nothing to do if this module is the source during bind */
+	if (dev->ipc_config.id == src_id)
+		return 0;
+
+	source_dev = ipc4_get_comp_dev(src_id);
+	if (!source_dev) {
+		comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id);
+		return -EINVAL;
+	}
+
+	mod_source_info = module_source_info_acquire(mod->source_info);
+
+	source_index = find_module_source_index(mod_source_info, source_dev);
+	/*
+	 * this should never happen as source_info should have been already cleared in
+	 * module_adapter_unbind()
+	 */
+	if (source_index >= 0)
+		mod_source_info->sources[source_index] = NULL;
+
+	/* find an empty slot in the source_info array */
+	source_index = find_module_source_index(mod_source_info, NULL);
+	if (source_index < 0) {
+		/* no free slot in module source_info array */
+		comp_err(dev, "Too many inputs!");
+		module_source_info_release(mod_source_info);
+		return -ENOMEM;
+	}
+
+	/* set the source dev pointer */
+	mod_source_info->sources[source_index] = source_dev;
+
+	module_source_info_release(mod_source_info);
+
+	return 0;
+}
+
+int module_adapter_unbind(struct comp_dev *dev, void *data)
+{
+	struct module_source_info __sparse_cache *mod_source_info;
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct ipc4_module_bind_unbind *bu;
+	struct comp_dev *source_dev;
+	int source_index;
+	int src_id;
+	int ret;
+
+	ret = module_unbind(mod, data);
+	if (ret < 0)
+		return ret;
+
+	bu = (struct ipc4_module_bind_unbind *)data;
+	src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id);
+
+	mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev);
+
+	/* nothing to do if this module is the source during unbind */
+	if (dev->ipc_config.id == src_id)
+		return 0;
+
+	source_dev = ipc4_get_comp_dev(src_id);
+	if (!source_dev) {
+		comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id);
+		return -EINVAL;
+	}
+
+	mod_source_info = module_source_info_acquire(mod->source_info);
+
+	/* find the index of the source in the sources array and clear it */
+	source_index = find_module_source_index(mod_source_info, source_dev);
+	if (source_index >= 0)
+		mod_source_info->sources[source_index] = NULL;
+
+	module_source_info_release(mod_source_info);
+
+	return 0;
+}
+
+uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev,
+						 uint32_t stream_no, bool input)
+{
+	struct processing_module *mod = comp_get_drvdata(dev);
+	struct module_data *md = &mod->priv;
+
+	if (md->ops->endpoint_ops && md->ops->endpoint_ops->get_total_data_processed)
+		return md->ops->endpoint_ops->get_total_data_processed(dev, stream_no, input);
+
+	if (input)
+		return mod->total_data_produced;
+	else
+		return mod->total_data_consumed;
+}
+
diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h
index 28f5c0765d0c..1dd9a4bfb0ec 100644
--- a/src/include/sof/audio/module_adapter/module/generic.h
+++ b/src/include/sof/audio/module_adapter/module/generic.h
@@ -21,6 +21,19 @@
 #include "modules.h"
 #endif
 
+/*
+ * helpers to determine processing type
+ * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE
+ */
+#define IS_PROCESSING_MODE_AUDIO_STREAM(mod) \
+		(!!((struct module_data *)&(mod)->priv)->ops->process_audio_stream)
+
+#define IS_PROCESSING_MODE_RAW_DATA(mod) \
+		(!!((struct module_data *)&(mod)->priv)->ops->process_raw_data)
+
+#define IS_PROCESSING_MODE_SINK_SOURCE(mod) \
+		(!!((struct module_data *)&(mod)->priv)->ops->process)
+
 #define module_get_private_data(mod) (mod->priv.private)
 #define MAX_BLOB_SIZE 8192
 #define MODULE_MAX_SOURCES 8
@@ -368,4 +381,24 @@ static inline int module_process_stream(struct processing_module *mod,
 					     output_buffers, num_output_buffers);
 }
 
+int module_adapter_init_data(struct comp_dev *dev,
+			     struct module_config *dst,
+			     const struct comp_ipc_config *config,
+			     const void *spec);
+void module_adapter_reset_data(struct module_config *dst);
+void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev,
+			       struct comp_buffer *sink);
+void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params);
+uint32_t
+module_single_sink_setup(struct comp_dev *dev,
+			 struct comp_buffer __sparse_cache **source_c,
+			 struct comp_buffer __sparse_cache **sinks_c);
+uint32_t
+module_single_source_setup(struct comp_dev *dev,
+			   struct comp_buffer __sparse_cache **source_c,
+			   struct comp_buffer __sparse_cache **sinks_c);
+int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev);
+int module_adapter_audio_stream_type_copy(struct comp_dev *dev);
+int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev,
+			     int cmd);
 #endif /* __SOF_AUDIO_MODULE_GENERIC__ */
diff --git a/test/cmocka/src/audio/eq_fir/CMakeLists.txt b/test/cmocka/src/audio/eq_fir/CMakeLists.txt
index af9fa80d0b60..3369f2b97b06 100644
--- a/test/cmocka/src/audio/eq_fir/CMakeLists.txt
+++ b/test/cmocka/src/audio/eq_fir/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(audio_for_eq_fir STATIC
 	${PROJECT_SOURCE_DIR}/src/math/fir_hifi3.c
 	${PROJECT_SOURCE_DIR}/src/math/numbers.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c
+	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c
 	${PROJECT_SOURCE_DIR}/src/audio/buffer.c
 	${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c
diff --git a/test/cmocka/src/audio/eq_iir/CMakeLists.txt b/test/cmocka/src/audio/eq_iir/CMakeLists.txt
index a72903d1c1df..a520a22fa441 100644
--- a/test/cmocka/src/audio/eq_iir/CMakeLists.txt
+++ b/test/cmocka/src/audio/eq_iir/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(audio_for_eq_iir STATIC
 	${PROJECT_SOURCE_DIR}/src/math/iir_df2t_hifi3.c
 	${PROJECT_SOURCE_DIR}/src/math/numbers.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c
+	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c
 	${PROJECT_SOURCE_DIR}/src/audio/buffer.c
 	${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c
diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt
index e422dd6ebf96..01aebc99223e 100644
--- a/test/cmocka/src/audio/mixer/CMakeLists.txt
+++ b/test/cmocka/src/audio/mixer/CMakeLists.txt
@@ -11,6 +11,7 @@ cmocka_test(mixer
 	${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c
 	${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c
+	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c
 	${PROJECT_SOURCE_DIR}/src/audio/buffer.c
 	${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c
diff --git a/test/cmocka/src/audio/mux/CMakeLists.txt b/test/cmocka/src/audio/mux/CMakeLists.txt
index 59e3752599fc..c6f67ae89127 100644
--- a/test/cmocka/src/audio/mux/CMakeLists.txt
+++ b/test/cmocka/src/audio/mux/CMakeLists.txt
@@ -23,6 +23,7 @@ add_library(
 	${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c
 	${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c
+	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c
 )
 sof_append_relative_path_definitions(audio_mux)
diff --git a/test/cmocka/src/audio/volume/CMakeLists.txt b/test/cmocka/src/audio/volume/CMakeLists.txt
index a1cd1fd8cab2..f6530bc2b3b0 100644
--- a/test/cmocka/src/audio/volume/CMakeLists.txt
+++ b/test/cmocka/src/audio/volume/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(audio_for_volume STATIC
 	${PROJECT_SOURCE_DIR}/src/audio/volume/volume_hifi3_with_peakvol.c
 	${PROJECT_SOURCE_DIR}/src/audio/volume/volume_hifi4_with_peakvol.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c
+	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c
 	${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c
 	${PROJECT_SOURCE_DIR}/src/audio/buffer.c
 	${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt
index e531eaabb690..12de15cfcde4 100644
--- a/zephyr/CMakeLists.txt
+++ b/zephyr/CMakeLists.txt
@@ -521,10 +521,19 @@ elseif(CONFIG_IPC_MAJOR_4)
 )
 endif()
 
+if(CONFIG_IPC_MAJOR_3)
 zephyr_library_sources_ifdef(CONFIG_COMP_MODULE_ADAPTER
 	${SOF_AUDIO_PATH}/module_adapter/module_adapter.c
+	${SOF_AUDIO_PATH}/module_adapter/module_adapter_ipc3.c
 	${SOF_AUDIO_PATH}/module_adapter/module/generic.c
 )
+elseif(CONFIG_IPC_MAJOR_4)
+zephyr_library_sources_ifdef(CONFIG_COMP_MODULE_ADAPTER
+	${SOF_AUDIO_PATH}/module_adapter/module_adapter.c
+	${SOF_AUDIO_PATH}/module_adapter/module_adapter_ipc4.c
+	${SOF_AUDIO_PATH}/module_adapter/module/generic.c
+)
+endif()
 
 zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER
 	${SOF_SRC_PATH}/library_manager/lib_manager.c