diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
index 8c01b1710da3ebaa48e5a9ed20876fbac9fe7180..1bca9613f6b1e53d62e7129faf851f56a51aaf6b 100644
--- a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
@@ -21,6 +21,15 @@
 #include "eformat/Issue.h"
 #include "eformat/SourceIdentifier.h"
 
+// Local definitions
+namespace {
+  /**
+   * ROBFragment module ID of the HLT result which contains all Trigger EDM collections. Can be considered to be made
+   * a property set from the EDM configuration to avoid multiple definitions, but the value should never change from 0.
+   */
+  constexpr uint16_t fullResultModuleId = 0;
+}
+
 // =============================================================================
 // Standard constructor
 // =============================================================================
@@ -117,26 +126,48 @@ StatusCode HLT::HLTResultMTByteStreamCnv::createRep(DataObject* pObj, IOpaqueAdd
   const std::vector<uint32_t>& hltBits = hltResult->getHltBitsAsWords();
   re->hlt_info(hltBits.size(), hltBits.data());
 
+  // Read the stream tags to decide which HLT ROBFragments to write out
+  std::set<eformat::helper::SourceIdentifier> resultIdsToWrite;
+  for (const eformat::helper::StreamTag& st : hltResult->getStreamTags()) {
+    // In case of full event building, add the full result ID
+    if (st.robs.empty() && st.dets.empty()) {
+      eformat::helper::SourceIdentifier sid(eformat::SubDetector::TDAQ_HLT, fullResultModuleId);
+      resultIdsToWrite.insert(sid);
+    }
+    // In case of partial event building, add the results explicitly requested in the stream tag
+    for (const uint32_t robid : st.robs) {
+      eformat::helper::SourceIdentifier sid(robid);
+      if (sid.subdetector_id() == eformat::SubDetector::TDAQ_HLT)
+        resultIdsToWrite.insert(sid);
+    }
+  }
+
   // Clear the FEA stack
   m_fullEventAssembler.clear();
 
-  // Loop over all module IDs and fill the ROBFragments
-  ATH_MSG_DEBUG("Iterating over modules to assemble output data");
-  for (const auto& p : hltResult->getSerialisedData()) {
-    const uint16_t moduleId = p.first;
-    const std::vector<uint32_t>& data = p.second;
+  // Loop over the module IDs and fill the ROBFragments
+  ATH_MSG_DEBUG("Iterating over " << resultIdsToWrite.size() << " HLT result IDs to assemble output data");
+  const std::unordered_map<uint16_t, std::vector<uint32_t>>& serialisedData = hltResult->getSerialisedData();
+  for (const eformat::helper::SourceIdentifier& resultId : resultIdsToWrite) {
+    // Find the serialised data for this module ID
+    const auto it = serialisedData.find(resultId.module_id());
+    if (it==serialisedData.end()) {
+      ATH_MSG_ERROR("HLT result with ID 0x" << MSG::hex << resultId.code() << MSG::dec
+                    << " requested by a stream tag, but missing in the serialised data");
+      return StatusCode::FAILURE;
+    }
+    const std::vector<uint32_t>& data = it->second;
 
     // Get a pointer to ROD data vector to be filled
-    eformat::helper::SourceIdentifier sid(eformat::TDAQ_HLT,moduleId);
-    std::vector<uint32_t>* rod = m_fullEventAssembler.getRodData(sid.code());
+    std::vector<uint32_t>* rod = m_fullEventAssembler.getRodData(resultId.code());
     if (!rod) {
-      ATH_MSG_ERROR("Failed to get RODDATA pointer for module " << sid.code());
+      ATH_MSG_ERROR("Failed to get RODDATA pointer for HLT result ID 0x" << MSG::hex << resultId.code() << MSG::dec);
       return StatusCode::FAILURE;
     }
 
     // Fill the ROD data vector
     rod->assign(data.cbegin(), data.cend());
-    ATH_MSG_DEBUG("Assembled data for module 0x" << MSG::hex << sid.code() << MSG::dec << " with "
+    ATH_MSG_DEBUG("Assembled data for HLT result ID 0x" << MSG::hex << resultId.code() << MSG::dec << " with "
                   << data.size() << " words of serialised payload");
   }