diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
index 56d42f2eb6e2..d26ed2a6029f 100644
--- a/sound/soc/sof/ipc4-control.c
+++ b/sound/soc/sof/ipc4-control.c
@@ -181,11 +181,237 @@ static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
 	return 0;
 }
 
+static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
+				       struct snd_sof_control *scontrol,
+				       bool set, bool lock)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct sof_abi_hdr *data = cdata->data;
+	struct sof_ipc4_msg *msg = &cdata->msg;
+	int ret = 0;
+
+	/* Send the new data to the firmware only if it is powered up */
+	if (set && !pm_runtime_active(sdev->dev))
+		return 0;
+
+	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
+
+	msg->data_ptr = data->data;
+	msg->data_size = data->size;
+
+	ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock);
+	if (ret < 0)
+		dev_err(sdev->dev, "Failed to %s for %s\n",
+			set ? "set bytes update" : "get bytes",
+			scontrol->name);
+
+	msg->data_ptr = NULL;
+	msg->data_size = 0;
+
+	return ret;
+}
+
+static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_abi_hdr *data = cdata->data;
+	size_t size;
+
+	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
+		dev_err_ratelimited(scomp->dev,
+				    "data max %zu exceeds ucontrol data array size\n",
+				    scontrol->max_size);
+		return -EINVAL;
+	}
+
+	/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
+	if (data->size > scontrol->max_size - sizeof(*data)) {
+		dev_err_ratelimited(scomp->dev,
+				    "data size too big %u bytes max is %zu\n",
+				    data->size, scontrol->max_size - sizeof(*data));
+		return -EINVAL;
+	}
+
+	size = data->size + sizeof(*data);
+
+	/* copy from kcontrol */
+	memcpy(data, ucontrol->value.bytes.data, size);
+
+	sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
+
+	return 0;
+}
+
+static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct sof_abi_hdr *data = cdata->data;
+	size_t size;
+
+	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
+		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
+				    scontrol->max_size);
+		return -EINVAL;
+	}
+
+	if (data->size > scontrol->max_size - sizeof(*data)) {
+		dev_err_ratelimited(scomp->dev,
+				    "%u bytes of control data is invalid, max is %zu\n",
+				    data->size, scontrol->max_size - sizeof(*data));
+		return -EINVAL;
+	}
+
+	size = data->size + sizeof(*data);
+
+	/* copy back to kcontrol */
+	memcpy(ucontrol->value.bytes.data, data, size);
+
+	return 0;
+}
+
+static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
+				  const unsigned int __user *binary_data,
+				  unsigned int size)
+{
+	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_abi_hdr *data = cdata->data;
+	struct sof_abi_hdr abi_hdr;
+	struct snd_ctl_tlv header;
+
+	/*
+	 * The beginning of bytes data contains a header from where
+	 * the length (as bytes) is needed to know the correct copy
+	 * length of data from tlvd->tlv.
+	 */
+	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
+		return -EFAULT;
+
+	/* make sure TLV info is consistent */
+	if (header.length + sizeof(struct snd_ctl_tlv) > size) {
+		dev_err_ratelimited(scomp->dev,
+				    "Inconsistent TLV, data %d + header %zu > %d\n",
+				    header.length, sizeof(struct snd_ctl_tlv), size);
+		return -EINVAL;
+	}
+
+	/* be->max is coming from topology */
+	if (header.length > scontrol->max_size) {
+		dev_err_ratelimited(scomp->dev,
+				    "Bytes data size %d exceeds max %zu\n",
+				    header.length, scontrol->max_size);
+		return -EINVAL;
+	}
+
+	/* Verify the ABI header first */
+	if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
+		return -EFAULT;
+
+	if (abi_hdr.magic != SOF_IPC4_ABI_MAGIC) {
+		dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n",
+				    abi_hdr.magic);
+		return -EINVAL;
+	}
+
+	if (abi_hdr.size > scontrol->max_size - sizeof(abi_hdr)) {
+		dev_err_ratelimited(scomp->dev,
+				    "%u bytes of control data is invalid, max is %zu\n",
+				    abi_hdr.size, scontrol->max_size - sizeof(abi_hdr));
+		return -EINVAL;
+	}
+
+	/* Copy the whole binary data which includes the ABI header and the payload */
+	if (copy_from_user(data, tlvd->tlv, header.length))
+		return -EFAULT;
+
+	sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
+
+	return 0;
+}
+
+static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
+				   const unsigned int __user *binary_data,
+				   unsigned int size, bool from_dsp)
+{
+	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct sof_abi_hdr *data = cdata->data;
+	struct snd_ctl_tlv header;
+	size_t data_size;
+
+	/*
+	 * Decrement the limit by ext bytes header size to ensure the user space
+	 * buffer is not exceeded.
+	 */
+	if (size < sizeof(struct snd_ctl_tlv))
+		return -ENOSPC;
+
+	size -= sizeof(struct snd_ctl_tlv);
+
+	/* get all the component data from DSP */
+	if (from_dsp) {
+		struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+		int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true);
+
+		if (ret < 0)
+			return ret;
+
+		/* Set the ABI magic (if the control is not initialized) */
+		data->magic = SOF_IPC4_ABI_MAGIC;
+	}
+
+	if (data->size > scontrol->max_size - sizeof(*data)) {
+		dev_err_ratelimited(scomp->dev,
+				    "%u bytes of control data is invalid, max is %zu\n",
+				    data->size, scontrol->max_size - sizeof(*data));
+		return -EINVAL;
+	}
+
+	data_size = data->size + sizeof(struct sof_abi_hdr);
+
+	/* make sure we don't exceed size provided by user space for data */
+	if (data_size > size)
+		return -ENOSPC;
+
+	header.numid = scontrol->comp_id;
+	header.length = data_size;
+
+	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
+		return -EFAULT;
+
+	if (copy_to_user(tlvd->tlv, data, data_size))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
+				  const unsigned int __user *binary_data,
+				  unsigned int size)
+{
+	return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false);
+}
+
+static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
+					   const unsigned int __user *binary_data,
+					   unsigned int size)
+{
+	return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
+}
+
 /* set up all controls for the widget */
 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
 {
 	struct snd_sof_control *scontrol;
-	int ret;
+	int ret = 0;
 
 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
 		if (scontrol->comp_id == swidget->comp_id) {
@@ -195,11 +421,10 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
 			case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
 				ret = sof_ipc4_set_volume_data(sdev, swidget,
 							       scontrol, false);
-				if (ret < 0) {
-					dev_err(sdev->dev, "kcontrol %d set up failed for widget %s\n",
-						scontrol->comp_id, swidget->widget->name);
-					return ret;
-				}
+				break;
+			case SND_SOC_TPLG_CTL_BYTES:
+				ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
+								  true, false);
 				break;
 			default:
 				break;
@@ -207,7 +432,11 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
 		}
 	}
 
-	return 0;
+	if (ret < 0)
+		dev_err(sdev->dev, "kcontrol %d set up failed for widget %s\n",
+			scontrol->comp_id, swidget->widget->name);
+
+	return ret;
 }
 
 static int
@@ -235,6 +464,11 @@ sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_I
 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
 	.volume_put = sof_ipc4_volume_put,
 	.volume_get = sof_ipc4_volume_get,
+	.bytes_put = sof_ipc4_bytes_put,
+	.bytes_get = sof_ipc4_bytes_get,
+	.bytes_ext_put = sof_ipc4_bytes_ext_put,
+	.bytes_ext_get = sof_ipc4_bytes_ext_get,
+	.bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
 	.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
 	.set_up_volume_table = sof_ipc4_set_up_volume_table,
 };
