diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 2e1200d17d0c..025b4d2ba0fe 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -574,6 +574,8 @@ static inline int snd_pcm_suspend_all(struct snd_pcm *pcm)
 }
 #endif
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
+struct snd_pcm_runtime *snd_pcm_runtime_alloc(void);
+void snd_pcm_runtime_free(struct snd_pcm_runtime *runtime);
 int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
 			   struct snd_pcm_substream **rsubstream);
 void snd_pcm_release_substream(struct snd_pcm_substream *substream);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index b163164a83ec..8ecb14b27460 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -876,6 +876,53 @@ static int snd_pcm_dev_free(struct snd_device *device)
 	return snd_pcm_free(pcm);
 }
 
+struct snd_pcm_runtime *snd_pcm_runtime_alloc(void)
+{
+	struct snd_pcm_runtime *runtime;
+	size_t size;
+
+	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+	if (!runtime)
+		return NULL;
+
+	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
+	runtime->status = alloc_pages_exact(size, GFP_KERNEL);
+	if (!runtime->status) {
+		kfree(runtime);
+		return NULL;
+	}
+	memset(runtime->status, 0, size);
+
+	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
+	runtime->control = alloc_pages_exact(size, GFP_KERNEL);
+	if (!runtime->control) {
+		free_pages_exact(runtime->status,
+				 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
+		kfree(runtime);
+		return NULL;
+	}
+	memset(runtime->control, 0, size);
+
+	init_waitqueue_head(&runtime->sleep);
+	init_waitqueue_head(&runtime->tsleep);
+
+	runtime->status->state = SNDRV_PCM_STATE_OPEN;
+
+	return runtime;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_runtime_alloc);
+
+void snd_pcm_runtime_free(struct snd_pcm_runtime *runtime)
+{
+	free_pages_exact(runtime->status,
+			 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
+	free_pages_exact(runtime->control,
+			 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
+	kfree(runtime->hw_constraints.rules);
+	kfree(runtime);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_runtime_free);
+
 int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 			     struct file *file,
 			     struct snd_pcm_substream **rsubstream)
@@ -885,7 +932,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 	struct snd_pcm_runtime *runtime;
 	struct snd_card *card;
 	int prefer_subdevice;
-	size_t size;
 
 	if (snd_BUG_ON(!pcm || !rsubstream))
 		return -ENXIO;
@@ -939,33 +985,10 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 	if (substream == NULL)
 		return -EAGAIN;
 
-	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
-	if (runtime == NULL)
+	runtime = snd_pcm_runtime_alloc();
+	if (!runtime)
 		return -ENOMEM;
 
-	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
-	runtime->status = alloc_pages_exact(size, GFP_KERNEL);
-	if (runtime->status == NULL) {
-		kfree(runtime);
-		return -ENOMEM;
-	}
-	memset(runtime->status, 0, size);
-
-	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
-	runtime->control = alloc_pages_exact(size, GFP_KERNEL);
-	if (runtime->control == NULL) {
-		free_pages_exact(runtime->status,
-			       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
-		kfree(runtime);
-		return -ENOMEM;
-	}
-	memset(runtime->control, 0, size);
-
-	init_waitqueue_head(&runtime->sleep);
-	init_waitqueue_head(&runtime->tsleep);
-
-	runtime->status->state = SNDRV_PCM_STATE_OPEN;
-
 	substream->runtime = runtime;
 	substream->private_data = pcm->private_data;
 	substream->ref_count = 1;
@@ -985,11 +1008,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
 	runtime = substream->runtime;
 	if (runtime->private_free != NULL)
 		runtime->private_free(runtime);
-	free_pages_exact(runtime->status,
-		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
-	free_pages_exact(runtime->control,
-		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
-	kfree(runtime->hw_constraints.rules);
 	/* Avoid concurrent access to runtime via PCM timer interface */
 	if (substream->timer) {
 		spin_lock_irq(&substream->timer->lock);
@@ -998,7 +1016,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
 	} else {
 		substream->runtime = NULL;
 	}
-	kfree(runtime);
+	snd_pcm_runtime_free(runtime);
 	put_pid(substream->pid);
 	substream->pid = NULL;
 	substream->pstr->substream_opened--;
