diff --git a/src/pcm/Dsd2Pcm.cxx b/src/pcm/Dsd2Pcm.cxx
index 6ce9ff9bb..777181094 100644
--- a/src/pcm/Dsd2Pcm.cxx
+++ b/src/pcm/Dsd2Pcm.cxx
@@ -213,9 +213,27 @@ MultiDsd2Pcm::Translate(unsigned channels, size_t n_frames,
 {
 	assert(channels <= per_channel.max_size());
 
+	if (channels == 2) {
+		TranslateStereo(n_frames, src, dest);
+		return;
+	}
+
 	for (unsigned i = 0; i < channels; ++i) {
 		per_channel[i].Translate(n_frames,
 					 src++, channels,
 					 dest++, channels);
 	}
 }
+
+inline void
+MultiDsd2Pcm::TranslateStereo(size_t n_frames,
+			      const uint8_t *src, float *dest) noexcept
+{
+	size_t ffp = fifopos;
+	while (n_frames-- > 0) {
+		*dest++ = per_channel[0].TranslateSample(ffp, *src++);
+		*dest++ = per_channel[1].TranslateSample(ffp, *src++);
+		ffp = (ffp + 1) & Dsd2Pcm::FIFOMASK;
+	}
+	fifopos = ffp;
+}
diff --git a/src/pcm/Dsd2Pcm.hxx b/src/pcm/Dsd2Pcm.hxx
index 561a428e4..a04004d5f 100644
--- a/src/pcm/Dsd2Pcm.hxx
+++ b/src/pcm/Dsd2Pcm.hxx
@@ -42,6 +42,8 @@ or implied, of Sebastian Gesemann.
  * A "dsd2pcm engine" for one channel.
  */
 class Dsd2Pcm {
+	friend class MultiDsd2Pcm;
+
 public:
 	/* must be a power of two */
 	static constexpr size_t FIFOSIZE = 16;
@@ -86,14 +88,24 @@ private:
 class MultiDsd2Pcm {
 	std::array<Dsd2Pcm, MAX_CHANNELS> per_channel;
 
+	size_t fifopos = 0;
+
 public:
 	void Reset() noexcept {
 		for (auto &i : per_channel)
 			i.Reset();
+		fifopos = 0;
 	}
 
 	void Translate(unsigned channels, size_t n_frames,
 		       const uint8_t *src, float *dest) noexcept;
+
+private:
+	/**
+	 * Optimized implementation for the common case.
+	 */
+	void TranslateStereo(size_t n_frames,
+			     const uint8_t *src, float *dest) noexcept;
 };
 
 #endif /* include guard DSD2PCM_H_INCLUDED */