return format_val;
 }
 
+static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
+                                           struct snd_pcm_substream *substream,
+                                           struct snd_pcm_hw_params *params)
+{
+       unsigned int format_val;
+       snd_pcm_format_t format;
+       unsigned int channels;
+       unsigned int width;
+
+       channels = params_channels(params);
+       format = params_format(params);
+       width = params_physical_width(params);
+
+       if (format == SNDRV_PCM_FORMAT_S16_LE) {
+               format = SNDRV_PCM_FORMAT_S32_LE;
+               channels /= 2;
+               width = 32;
+       }
+
+       format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
+                                                format,
+                                                width,
+                                                0);
+
+       dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+               params_rate(params), channels, format);
+
+       return format_val;
+}
+
 static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
                                           struct snd_pcm_substream *substream)
 {
        return hdac_bus_eml_ssp_get_hlink(bus);
 }
 
+static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
+                                           struct snd_pcm_substream *substream)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       return hdac_bus_eml_dmic_get_hlink(bus);
+}
+
 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                struct snd_pcm_substream *substream, int cmd)
 {
        .get_hlink = ssp_get_hlink,
 };
 
+static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
+       .get_hext_stream = hda_ipc4_get_hext_stream,
+       .assign_hext_stream = hda_assign_hext_stream,
+       .release_hext_stream = hda_release_hext_stream,
+       .setup_hext_stream = hda_setup_hext_stream,
+       .reset_hext_stream = hda_reset_hext_stream,
+       .pre_trigger = hda_ipc4_pre_trigger,
+       .trigger = hda_trigger,
+       .post_trigger = hda_ipc4_post_trigger,
+       .calc_stream_format = dmic_calc_stream_format,
+       .get_hlink = dmic_get_hlink,
+};
+
 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
        .get_hext_stream = hda_get_hext_stream,
        .assign_hext_stream = hda_assign_hext_stream,
                        if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
                                return NULL;
                        return &ssp_ipc4_dma_ops;
+               case SOF_DAI_INTEL_DMIC:
+                       if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+                               return NULL;
+                       return &dmic_ipc4_dma_ops;
                default:
                        break;
                }
 
        .prepare = non_hda_dai_prepare,
 };
 
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+       .hw_params = non_hda_dai_hw_params,
+       .hw_free = hda_dai_hw_free,
+       .trigger = hda_dai_trigger,
+       .prepare = non_hda_dai_prepare,
+};
+
 static int hda_dai_suspend(struct hdac_bus *bus)
 {
        struct snd_soc_pcm_runtime *rtd;
        }
 }
 
+static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+       const struct sof_intel_dsp_desc *chip;
+       int i;
+
+       chip = get_chip_info(sdev->pdata);
+
+       if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+               for (i = 0; i < ops->num_drv; i++) {
+                       if (strstr(ops->drv[i].name, "DMIC"))
+                               ops->drv[i].ops = &dmic_dai_ops;
+               }
+       }
+}
+
 #else
 
 static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
 
 #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
 
        }
 
        ssp_set_dai_drv_ops(sdev, ops);
+       dmic_set_dai_drv_ops(sdev, ops);
 
        if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
                struct sof_ipc4_fw_data *ipc4_data = sdev->private;