diff --git a/NEWS b/NEWS
index 21e28ee0b..efb10b604 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,7 @@ ver 0.22 (not yet released)
   - ffmpeg: new plugin based on FFmpeg's libavfilter library
   - hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback
   - volume: convert S16 to S24 to preserve quality and reduce dithering noise
+  - dsd: add integer-only DSD to PCM converter
 * output
   - jack: add option "auto_destination_ports"
   - jack: report error details
diff --git a/src/pcm/Convert.cxx b/src/pcm/Convert.cxx
index d464d210e..6f550ba94 100644
--- a/src/pcm/Convert.cxx
+++ b/src/pcm/Convert.cxx
@@ -41,7 +41,10 @@ PcmConvert::PcmConvert(const AudioFormat _src_format,
 	AudioFormat format = _src_format;
 	if (format.format == SampleFormat::DSD) {
 #ifdef ENABLE_DSD
-		format.format = SampleFormat::FLOAT;
+		dsd2pcm_float = dest_format.format == SampleFormat::FLOAT;
+		format.format = dsd2pcm_float
+			? SampleFormat::FLOAT
+			: SampleFormat::S24_P32;
 #else
 		throw std::runtime_error("DSD support is disabled");
 #endif
@@ -115,11 +118,13 @@ PcmConvert::Convert(ConstBuffer<void> buffer)
 #ifdef ENABLE_DSD
 	if (src_format.format == SampleFormat::DSD) {
 		auto s = ConstBuffer<uint8_t>::FromVoid(buffer);
-		auto d = dsd.ToFloat(src_format.channels, s);
+		auto d = dsd2pcm_float
+			? dsd.ToFloat(src_format.channels, s).ToVoid()
+			: dsd.ToS24(src_format.channels, s).ToVoid();
 		if (d.IsNull())
 			throw std::runtime_error("DSD to PCM conversion failed");
 
-		buffer = d.ToVoid();
+		buffer = d;
 	}
 #endif
 
diff --git a/src/pcm/Convert.hxx b/src/pcm/Convert.hxx
index c22241054..4a1143338 100644
--- a/src/pcm/Convert.hxx
+++ b/src/pcm/Convert.hxx
@@ -51,6 +51,10 @@ class PcmConvert {
 
 	bool enable_resampler, enable_format, enable_channels;
 
+#ifdef ENABLE_DSD
+	bool dsd2pcm_float;
+#endif
+
 public:
 
 	/**