return NULL;
        }
 
+       if (ops->init && ops->init(sdev))
+               return NULL;
+
        ipc->ops = ops;
 
        return ipc;
        mutex_lock(&ipc->tx_mutex);
        ipc->disable_ipc_tx = true;
        mutex_unlock(&ipc->tx_mutex);
+
+       if (ipc->ops->exit)
+               ipc->ops->exit(sdev);
 }
 EXPORT_SYMBOL(snd_sof_ipc_free);
 
  * @fw_loader: Pointer to Firmware Loader ops
  * @fw_tracing:        Pointer to Firmware tracing ops
  *
+ * @init:      Optional pointer for IPC related initialization
+ * @exit:      Optional pointer for IPC related cleanup
+ *
  * @tx_msg:    Function pointer for sending a 'short' IPC message
  * @set_get_data: Function pointer for set/get data ('large' IPC message). This
  *             function may split up the 'large' message and use the @tx_msg
        const struct sof_ipc_fw_loader_ops *fw_loader;
        const struct sof_ipc_fw_tracing_ops *fw_tracing;
 
+       int (*init)(struct snd_sof_dev *sdev);
+       void (*exit)(struct snd_sof_dev *sdev);
+
        int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
                      void *reply_data, size_t reply_bytes, bool no_pm);
        int (*set_get_data)(struct snd_sof_dev *sdev, void *data, size_t data_bytes,