diff --git a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
index 90a3ab512bd465b7b06c5caff32fb467a683254e..c7954c39a204248c3f235c4f417248a23584d2d4 100644
--- a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
@@ -29,6 +29,8 @@
 
 #include "GaudiKernel/Incident.h"
 
+#include <boost/dynamic_bitset.hpp>
+
 using namespace TrigDec;
 
 TrigDecisionMakerMT::TrigDecisionMakerMT(const std::string &name, ISvcLocator *pSvcLocator)
@@ -41,7 +43,7 @@ TrigDecisionMakerMT::~TrigDecisionMakerMT() {}
 
 StatusCode TrigDecisionMakerMT::initialize()
 {
-  ATH_CHECK( m_HLTSummaryKeyIn.initialize() );
+  ATH_CHECK( m_hltResultKeyIn.initialize() );
   ATH_CHECK( m_ROIBResultKeyIn.initialize() );
   ATH_CHECK( m_EventInfoKeyIn.initialize() );
 
@@ -86,7 +88,7 @@ StatusCode TrigDecisionMakerMT::execute(const EventContext& context) const
     }
   }
 
-  const DecisionContainer* hltResult = nullptr;
+  const HLT::HLTResultMT* hltResult = nullptr;
   if (m_doHLT) {
     ATH_CHECK(getHLTResult(hltResult, context));
   }
@@ -103,72 +105,32 @@ StatusCode TrigDecisionMakerMT::execute(const EventContext& context) const
     trigDec->setTBP(l1Result->itemsBeforePrescale());
   }
 
-  // Output bitsets (stored in a vector<uint32_t>)
-  std::vector<uint32_t> hltPassBits;
-  std::vector<uint32_t> hltPrescaledBits;
-  std::vector<uint32_t> hltRerunBits;
-
-  std::set< std::vector<uint32_t>* > outputVectors;
-  outputVectors.insert( &hltPassBits );
-  outputVectors.insert( &hltPrescaledBits );
-  outputVectors.insert( &hltRerunBits );
-
   if (hltResult) {
-    ATH_MSG_DEBUG("Got a DecisionContainer '" << m_HLTSummaryKeyIn.key() << "' of size " << hltResult->size());
-    const Decision* HLTPassRaw = nullptr;
-    const Decision* HLTPrescaled = nullptr;
-    const Decision* HLTRerun = nullptr;
-
-    DecisionIDContainer passRawInput; //!< The chains which returned a positive decision
-    DecisionIDContainer prescaledInput; //!< The chains which did not run due to being prescaled out
-    DecisionIDContainer rerunInput; //!< The chains which were activate only in the rerun (not physics decisions)
-
-    // Read the sets of chain IDs
-    for (const Decision* decisionObject : *hltResult) {
-      // Collect all decisions (IDs of passed/prescaled/rerun chains) from named decisionObjects
-      if (decisionObject->name() == "HLTPassRaw") {
-        HLTPassRaw = decisionObject;
-      } else if (decisionObject->name() == "HLTPrescaled") {
-        HLTPrescaled = decisionObject;
-      } else if (decisionObject->name() == "HLTRerun") {
-        HLTRerun = decisionObject;
-      }
-      if (HLTPassRaw && HLTPrescaled && HLTRerun) {
-        break;
-      }
-    }
 
-    ATH_CHECK(HLTPassRaw != nullptr);
-    ATH_CHECK(HLTPrescaled != nullptr);
-    ATH_CHECK(HLTRerun != nullptr);
+    std::vector<uint32_t> hltPassRawBits;
+    std::vector<uint32_t> hltPrescaledBits;
+    std::vector<uint32_t> hltRerunBits;
 
-    // Get all passed IDs.
-    decisionIDs(HLTPassRaw, passRawInput);
+    hltPassRawBits.resize(hltResult->getHltPassRawBits().num_blocks());
+    hltPrescaledBits.resize(hltResult->getHltPrescaledBits().num_blocks());
+    hltRerunBits.resize(hltResult->getHltRerunBits().num_blocks());
 
-    // Simpler structure for prescaled. 
-    decisionIDs(HLTPrescaled, prescaledInput);
+    boost::to_block_range(hltResult->getHltPassRawBits(),hltPassRawBits.begin());
+    boost::to_block_range(hltResult->getHltPrescaledBits(),hltPrescaledBits.begin());
+    boost::to_block_range(hltResult->getHltRerunBits(),hltRerunBits.begin());
 
-    // Get all passed IDs. 
-    decisionIDs(HLTRerun, rerunInput);   
+    ATH_MSG_DEBUG ("Number of HLT chains passed raw: " << hltResult->getHltPassRawBits().count());
+    ATH_MSG_DEBUG ("Number of HLT chains prescaled out: " << hltResult->getHltPrescaledBits().count());
+    ATH_MSG_DEBUG ("Number of HLT chains in rerun / second pass / resurrection : " << hltResult->getHltRerunBits().count());
+
+    trigDec->setEFPassedRaw(hltPassRawBits);
+    trigDec->setEFPrescaled(hltPrescaledBits);
+    trigDec->setEFResurrected(hltRerunBits);
 
-    if (passRawInput.size()) {
+    if (hltResult->getHltPassRawBits().any()) {
       ++m_hltPassed;
     }
-  
-    // Make bitmap for passed raw
-    size_t countHltPass = makeBitMap(passRawInput, hltPassBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains passed raw: " << countHltPass);
-    trigDec->setEFPassedRaw(hltPassBits);
-
-    // Make bitmap for prescaled
-    size_t countHltPrescaled = makeBitMap(prescaledInput, hltPrescaledBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains prescaled out: " << countHltPrescaled);
-    trigDec->setEFPrescaled(hltPrescaledBits);
 
-    // Make bitmap for rerun a.k.a. resurrection
-    size_t countHLTRerun = makeBitMap(rerunInput, hltRerunBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains in rerun / second pass / resurrection : " << countHLTRerun);
-    trigDec->setEFResurrected(hltRerunBits);
   }
 
   // get the bunch crossing id
@@ -209,9 +171,9 @@ StatusCode TrigDecisionMakerMT::getL1Result(const LVL1CTP::Lvl1Result*& result,
 }
 
 
-StatusCode TrigDecisionMakerMT::getHLTResult(const TrigCompositeUtils::DecisionContainer*& result, const EventContext& context) const
+StatusCode TrigDecisionMakerMT::getHLTResult(const HLT::HLTResultMT*& result, const EventContext& context) const
 {
-  result = SG::get(m_HLTSummaryKeyIn, context);
+  result = SG::get(m_hltResultKeyIn, context);
   return StatusCode::SUCCESS;
 }
 
@@ -228,55 +190,3 @@ char TrigDecisionMakerMT::getBGByte(int BCId) const {
   }
   return bgs->bgPattern()[BCId];  
 }
-
-
-size_t TrigDecisionMakerMT::makeBitMap(
-  const TrigCompositeUtils::DecisionIDContainer& passedIDs,
-  std::vector<uint32_t>& bitsVector,
-  std::set< std::vector<uint32_t>* >& allOutputVectors) const
-{
-  size_t count = 0;
-  for (const TrigCompositeUtils::DecisionID id : passedIDs) {
-    const int32_t chainCounter = getChainCounter(id);
-    if (chainCounter == -1) continue; // Could not decode, prints error
-    resizeVectors(chainCounter, allOutputVectors); // Make sure we have enough room to be able to set the required bit
-    setBit(chainCounter, bitsVector);
-    ++count;
-  }
-  return count;
-}
-
-
-void TrigDecisionMakerMT::resizeVectors(const size_t bit, const std::set< std::vector<uint32_t>* >& vectors) const {
-  const size_t block = bit / std::numeric_limits<uint32_t>::digits;
-  const size_t requiredSize = block + 1;
-  if (vectors.size() && requiredSize > (*vectors.begin())->size()) {
-    for (std::vector<uint32_t>* vecPtr : vectors) {
-      vecPtr->resize(requiredSize, 0); // Resize can shrink, here we only ever want to expand
-    }
-  }
-  return;
-}
-
-
-void TrigDecisionMakerMT::setBit(const size_t bit, std::vector<uint32_t>& bits) const {
-  const size_t block = bit / std::numeric_limits<uint32_t>::digits; // = 32
-  const size_t offset = bit % std::numeric_limits<uint32_t>::digits;
-  bits.at(block) |= static_cast<uint32_t>(1) << offset;
-}
-
-
-int32_t TrigDecisionMakerMT::getChainCounter(const TrigCompositeUtils::DecisionID chainID) const {
-  // Need to go from hash-ID to chain-counter. HLTChain counter currently does not give this a category
-  const std::string chainName = TrigConf::HLTUtils::hash2string(chainID);
-  if (chainName == "UNKNOWN HASH ID" || chainName == "UNKNOWN CATEGORY") {
-    ATH_MSG_ERROR("Unable to locate chain with hashID:" << chainID << " in the TrigConf, the error reported was: " << chainName);
-    return -1;
-  }
-  const TrigConf::HLTChain* chain = m_trigConfigSvc->chains().chain(chainName);
-  if (chain == nullptr) {
-    ATH_MSG_ERROR("Unable to fetch HLTChain object for chain with hashID:" << chainID << " and name:'" << chainName << "' (number of chains:" << m_trigConfigSvc->chains().size() << ")");
-    return -1;        
-  }
-  return chain->chain_counter();
-}
diff --git a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
index 4f6d53731dc05283ed42e38771648d41a55a7c4b..2e7a4707000e58b3dd23acae044322ebbdeb3511 100644
--- a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
+++ b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
@@ -30,10 +30,9 @@
 #include "xAODEventInfo/EventInfo.h"
 
 // trigger/configuration stuff
-#include "xAODTrigger/TrigCompositeContainer.h"
 #include "xAODTrigger/TrigDecision.h"
-#include "DecisionHandling/TrigCompositeUtils.h"
 #include "TrigT1Result/RoIBResult.h"
+#include "TrigSteeringEvent/HLTResultMT.h"
 
 // containers
 #include <vector>
@@ -79,41 +78,13 @@ namespace TrigDec {
     virtual StatusCode execute( const EventContext& context ) const override; //!< Re-entrant execute to create the xAOD::TrigDecision
     virtual StatusCode finalize() override;    //!< std Gaudi finalize method -> print out statistics
 
+  private:
+
     StatusCode getL1Result (const LVL1CTP::Lvl1Result*& result, const EventContext& context) const; //!< retrieve LVL1 result (called in execute)
-    StatusCode getHLTResult(const TrigCompositeUtils::DecisionContainer*& result, const EventContext& context) const; //!< retrieve HLT results (called in execute)
+    StatusCode getHLTResult(const HLT::HLTResultMT*& result, const EventContext& context) const; //!< retrieve HLT results (called in execute)
 
     char getBGByte(int BCId) const; //!< to get the BG byte encoded for a given BC
 
-  private:
-
-    /**
-     * @brief Ensures that the supplied vectors have sufficient capacity to store the given bit, where bits are packed into uint32_t.
-     * @param bit The bit we wish the vectors to be large enough to store
-     * @param vectors Set of pointers to all vectors which need resizing. Note, while the set of pointers is const, the vectors are not const.
-     **/  
-    void resizeVectors(const size_t bit, const std::set< std::vector<uint32_t>* >& vectors) const;
-
-    /**
-     * @param bit The bit to set to 1 (bit 0 equates to the first bit). Requires the vector to have already been resized to be large enough.
-     * @param bits The vector to set the bit in.
-     **/
-    void setBit(const size_t bit, std::vector<uint32_t>& bits) const;
-
-    /**
-     * @param chainID The identifier (name hash) of the chain to fetch the ChainCounter for.
-     * @return the Chain Counter or -1 if error.
-     **/
-    int32_t getChainCounter(const TrigCompositeUtils::DecisionID chainID) const;
-
-    /**
-     * @param passedIDs Set of IDs of passed chains.
-     * @param bitsVector Vector to set passed-bits in based off of passedIDs
-     * @param allOutputVectors Set of pointers to *all* output vectors, keeps them all the same size
-     * @return the number of positive bits set in the vector, should be the same as passedIDs.size()
-     **/
-    size_t makeBitMap(const TrigCompositeUtils::DecisionIDContainer& passedIDs,
-      std::vector<uint32_t>& bitsVector, std::set< std::vector<uint32_t>* >& allOutputVectors) const;
-
     Gaudi::Property<bool> m_doL1{this, "doL1",  true, "Read L1 trigger information"};
     Gaudi::Property<bool> m_doHLT{this, "doHLT", true, "Read HLT trigger information"};
 
@@ -125,7 +96,7 @@ namespace TrigDec {
     Gaudi::Property<std::string> m_lvl1ToolLocation{this, "Lvl1ToolLocation", "HLT::Lvl1ResultAccessTool/Lvl1ResultAccessTool", "L1 tool to fetch"};
 
     // Input keys configuration
-    SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_HLTSummaryKeyIn {this, "HLTSummary", "HLTNav_Summary", "HLT summary container Key"};
+    SG::ReadHandleKey<HLT::HLTResultMT> m_hltResultKeyIn {this, "HLTResultMT", "HLTResultMT", "Key of the HLTResultMT object" };
     SG::ReadHandleKey<LVL1CTP::Lvl1Result> m_L1ResultKeyIn {this, "Lvl1Result", "Lvl1Result", "Lvl1 Result Object Key"};
     SG::ReadHandleKey<ROIB::RoIBResult> m_ROIBResultKeyIn {this, "RoIBResult", "RoIBResult", "RoIB Result Object Key"};
     SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKeyIn {this, "EventInfo", "EventInfo", "Event Info Object Key"};
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
index 64208fd5d22ceafc7a3ad45c38fa8d9633d6f874..2198ee83adee500cf2f53a5e281249951113d98d 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
@@ -34,7 +34,9 @@ namespace HLT {
   public:
     /// Standard constructor
     HLTResultMT(std::vector<eformat::helper::StreamTag> streamTags = {},
-                boost::dynamic_bitset<uint32_t> hltBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltPassRawBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltPrescaledBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltRerunBits = boost::dynamic_bitset<uint32_t>(),
                 std::unordered_map<uint16_t, std::vector<uint32_t> > data = {},
                 std::vector<uint32_t> status = {0});
 
@@ -64,25 +66,70 @@ namespace HLT {
 
     // ------------------------- HLT bits getters/setters ----------------------
 
-    /// Const-getter for HLT bits
-    const boost::dynamic_bitset<uint32_t>& getHltBits() const;
+    /// Const-getter for HLT pass raw bits
+    const boost::dynamic_bitset<uint32_t>& getHltPassRawBits() const;
 
-    /// Const-getter for HLT bits as uint32_t array
+    /// Const-getter for HLT prescaled bits
+    const boost::dynamic_bitset<uint32_t>& getHltPrescaledBits() const;
+
+    /// Const-getter for HLT rerun bits
+    const boost::dynamic_bitset<uint32_t>& getHltRerunBits() const;
+
+    /// Const-getter for HLT bits as uint32_t array. Ordering: PassRaw, Prescaled, Rerun.
     const std::vector<uint32_t>& getHltBitsAsWords();
 
-    /// Replace HLT bits with the given bitset
-    void setHltBits(const boost::dynamic_bitset<uint32_t>& bitset);
+    /** @brief Reserve space for HLT bits
+     *  @param numberOfChains Number of chains configured in the menu
+     *  @return FAILURE on memory allocation error
+     **/
+    StatusCode reserveHltBits(size_t numberOfChains);
+
+    /// Replace HLT pass raw bits with the given bitset
+    void setHltPassRawBits(const boost::dynamic_bitset<uint32_t>& bitset);
+
+    /// Replace HLT prescaled bits with the given bitset
+    void setHltPrescaledBits(const boost::dynamic_bitset<uint32_t>& bitset);
+
+    /// Replace HLT rerun raw bits with the given bitset
+    void setHltRerunBits(const boost::dynamic_bitset<uint32_t>& bitset);
 
     /** @brief Sets bit at the given index to true
-     *  @return FAILURE on memory allocation error
+     *  @return FAILURE on memory error
+     **/
+    StatusCode addHltPassRawBit(size_t index);
+
+    /** @brief Sets bit at the given index to true
+     *  @return FAILURE on memory error
      **/
-    StatusCode addHltBit(size_t index);
+    StatusCode addHltPrescaledBit(size_t index);
+
+    /** @brief Sets bit at the given index to true
+     *  @return FAILURE on memory error
+     **/
+    StatusCode addHltRerunBit(size_t index);
 
     /** @brief Sets bits at the given indices to true
-     *  @return FAILURE on memory allocation error
+     *  @return FAILURE on memory error
+     **/
+    StatusCode addHltPassRawBits(const std::vector<size_t>& indices);
+
+    /** @brief Sets bits at the given indices to true
+     *  @return FAILURE on memory error
+     **/
+    StatusCode addHltPrescaledBits(const std::vector<size_t>& indices);
+
+    /** @brief Sets bits at the given indices to true
+     *  @return FAILURE on memory error
      **/
-    StatusCode addHltBits(const std::vector<size_t>& indices);
+    StatusCode addHltRerunBits(const std::vector<size_t>& indices);
+
 
+    /** @brief Intnernally sets bit at the given indices to true
+     *  @return FAILURE on memory error
+     **/
+  private:
+    StatusCode addHltBitInternal(size_t index, boost::dynamic_bitset<uint32_t>& bitset);
+  public:
 
     // ------------------------- Serialised data getters/setters ---------------
 
@@ -152,12 +199,14 @@ namespace HLT {
     std::vector<eformat::helper::StreamTag> m_streamTags;
 
     /// HLT bits (flagging which chains passed)
-    boost::dynamic_bitset<uint32_t> m_hltBits;
+    boost::dynamic_bitset<uint32_t> m_hltPassRawBits;
+    boost::dynamic_bitset<uint32_t> m_hltPrescaledBits;
+    boost::dynamic_bitset<uint32_t> m_hltRerunBits;
 
     /** @brief Vector storing m_hltBits converted to 4-byte words
      *
      *  HLTResultMT needs to own this vector because its lifetime has to be ensured until the serialisation is finished.
-     *  This vector is updated internally from m_hltBits and does not have a setter method.
+     *  This vector is updated internally from m_hltPassRawBits, m_hltPrescaledBits, m_hltRerunBits and does not have a setter method.
      **/
     std::vector<uint32_t> m_hltBitWords;
 
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
index 873d3a2db6df17c28e35127a1790bcc9f87d0310..5cd7623d59db634401b67e32f6d982767a20122a 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
+++ b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
@@ -12,11 +12,15 @@
 // Standard constructor
 // =============================================================================
 HLT::HLTResultMT::HLTResultMT(std::vector<eformat::helper::StreamTag> streamTags,
-                              boost::dynamic_bitset<uint32_t> hltBits,
+                              boost::dynamic_bitset<uint32_t> hltPassRawBits,
+                              boost::dynamic_bitset<uint32_t> hltPrescaledBits,
+                              boost::dynamic_bitset<uint32_t> hltRerunBits,
                               std::unordered_map<uint16_t, std::vector<uint32_t> > data,
                               std::vector<uint32_t> status)
 : m_streamTags(streamTags),
-  m_hltBits(hltBits),
+  m_hltPassRawBits(hltPassRawBits),
+  m_hltPrescaledBits(hltPrescaledBits),
+  m_hltRerunBits(hltRerunBits),
   m_data(data),
   m_status(status) {}
 
@@ -70,47 +74,127 @@ StatusCode HLT::HLTResultMT::addStreamTag(const eformat::helper::StreamTag& stre
 // =============================================================================
 // Getter/setter methods for trigger bits
 // =============================================================================
-const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltBits() const {
-  return m_hltBits;
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltPassRawBits() const {
+  return m_hltPassRawBits;
+}
+
+// -----------------------------------------------------------------------------
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltPrescaledBits() const {
+  return m_hltPrescaledBits;
+}
+
+// -----------------------------------------------------------------------------
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltRerunBits() const {
+  return m_hltRerunBits;
 }
 
 // -----------------------------------------------------------------------------
 const std::vector<uint32_t>& HLT::HLTResultMT::getHltBitsAsWords() {
   m_hltBitWords.clear();
-  m_hltBitWords.resize(m_hltBits.num_blocks());
-  boost::to_block_range(m_hltBits,m_hltBitWords.begin());
+  if (m_hltPassRawBits.num_blocks() != m_hltPrescaledBits.num_blocks() || m_hltPassRawBits.num_blocks() != m_hltRerunBits.num_blocks()) {
+    throw std::runtime_error("Must have the same number of bits in m_hltPassRawBits, m_hltPrescaledBits and m_hltRerunBits.");
+  }
+  m_hltBitWords.resize(m_hltPassRawBits.num_blocks() + m_hltPrescaledBits.num_blocks() + m_hltRerunBits.num_blocks());
+  boost::to_block_range(m_hltPassRawBits, m_hltBitWords.begin());
+  boost::to_block_range(m_hltPrescaledBits, m_hltBitWords.begin());
+  boost::to_block_range(m_hltRerunBits, m_hltBitWords.begin());
   return m_hltBitWords;
 }
 
 // -----------------------------------------------------------------------------
-void HLT::HLTResultMT::setHltBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+void HLT::HLTResultMT::setHltPassRawBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+  // copy assignment
+  m_hltPassRawBits = bitset;
+}
+
+// -----------------------------------------------------------------------------
+void HLT::HLTResultMT::setHltPrescaledBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+  // copy assignment
+  m_hltPrescaledBits = bitset;
+}
+
+// -----------------------------------------------------------------------------
+void HLT::HLTResultMT::setHltRerunBits(const boost::dynamic_bitset<uint32_t>& bitset) {
   // copy assignment
-  m_hltBits = bitset;
+  m_hltRerunBits = bitset;
 }
 
 // -----------------------------------------------------------------------------
-StatusCode HLT::HLTResultMT::addHltBit(size_t index) {
+StatusCode HLT::HLTResultMT::reserveHltBits(size_t numberOfChains) {
   try {
-    if (m_hltBits.size() <= index) m_hltBits.resize(index+1);
-    m_hltBits.set(index);
+    if (m_hltPassRawBits.size() <= numberOfChains) m_hltPassRawBits.resize(numberOfChains+1);
+    if (m_hltPrescaledBits.size() <= numberOfChains) m_hltPrescaledBits.resize(numberOfChains+1);
+    if (m_hltRerunBits.size() <= numberOfChains) m_hltRerunBits.resize(numberOfChains+1);
   }
   catch (const std::exception& ex) {
     ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
-      << "Failed to add HLT bit, likely memory allocation failed. std::exception caught: " << ex.what();
+      << "Failed to reserve space for " << numberOfChains << " HLT bits, likely memory allocation failed. std::exception caught: " << ex.what();
     return StatusCode::FAILURE;
   }
   catch (...) {
     ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
-      << "Failed to add HLT bit, likely memory allocation failed. Unknown exception caught.";
+      << "Failed to  reserve space for " << numberOfChains << " HLT bits, likely memory allocation failed. Unknown exception caught.";
     return StatusCode::FAILURE;
   }
   return StatusCode::SUCCESS;
 }
 
 // -----------------------------------------------------------------------------
-StatusCode HLT::HLTResultMT::addHltBits(const std::vector<size_t>& indices) {
+StatusCode HLT::HLTResultMT::addHltPassRawBits(const std::vector<size_t>& indices) {
   for (const size_t index : indices) {
-    ATH_CHECK(addHltBit(index));
+    ATH_CHECK(addHltPassRawBit(index));
+  }
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltPrescaledBits(const std::vector<size_t>& indices) {
+  for (const size_t index : indices) {
+    ATH_CHECK(addHltPrescaledBit(index));
+  }
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltRerunBits(const std::vector<size_t>& indices) {
+  for (const size_t index : indices) {
+    ATH_CHECK(addHltRerunBit(index));
+  }
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltPassRawBit(size_t index) {
+  ATH_CHECK(addHltBitInternal(index, m_hltPassRawBits));
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltPrescaledBit(size_t index) {
+  ATH_CHECK(addHltBitInternal(index, m_hltPrescaledBits));
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltRerunBit(size_t index) {
+  ATH_CHECK(addHltBitInternal(index, m_hltRerunBits));
+  return StatusCode::SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+StatusCode HLT::HLTResultMT::addHltBitInternal(size_t index, boost::dynamic_bitset<uint32_t>& bitset) {
+  try {
+    bitset.set(index);
+  }
+  catch (const std::exception& ex) {
+    ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
+      << "Failed to add HLT bit, likely memory allocation failed. Was reserveHltBits() called? std::exception caught: " << ex.what();
+    return StatusCode::FAILURE;
+  }
+  catch (...) {
+    ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
+      << "Failed to add HLT bit, likely memory allocation failed. Was reserveHltBits() called? Unknown exception caught.";
+    return StatusCode::FAILURE;
   }
   return StatusCode::SUCCESS;
 }
@@ -238,11 +322,23 @@ std::ostream& operator<<(std::ostream& str, const HLT::HLTResultMT& hltResult) {
   if (hltResult.getStreamTags().empty()) str << std::endl;
 
   // HLT bits
-  std::vector<uint32_t> hltBitWords;
-  hltBitWords.resize(hltResult.getHltBits().num_blocks());
-  boost::to_block_range(hltResult.getHltBits(),hltBitWords.begin());
+  std::vector<uint32_t> hltPassRawBitWords;
+  std::vector<uint32_t> hltPrescaledBitWords;
+  std::vector<uint32_t> hltRerunBitWords;
+  hltPassRawBitWords.resize(hltResult.getHltPassRawBits().num_blocks());
+  hltPrescaledBitWords.resize(hltResult.getHltPrescaledBits().num_blocks());
+  hltRerunBitWords.resize(hltResult.getHltRerunBits().num_blocks());
+  boost::to_block_range(hltResult.getHltPassRawBits(),hltPassRawBitWords.begin());
+  boost::to_block_range(hltResult.getHltPrescaledBits(),hltPrescaledBitWords.begin());
+  boost::to_block_range(hltResult.getHltRerunBits(),hltRerunBitWords.begin());
   str << "--> HLT bits     = ";
-  for (const uint32_t word : hltBitWords) {
+  for (const uint32_t word : hltPassRawBitWords) {
+    printWord(word);
+  }
+  for (const uint32_t word : hltPrescaledBitWords) {
+    printWord(word);
+  }
+  for (const uint32_t word : hltRerunBitWords) {
     printWord(word);
   }
   str << std::endl;
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
index 99388b31738b9b79f06e9c981e0522dda6075979..55ed8066229073cc00ff6a7a31e645ffb3f7e837 100644
--- a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
@@ -101,9 +101,19 @@ StatusCode HLTResultMTByteStreamDecoderTool::decodeHeader(const RawEvent* rawEve
     ATH_MSG_ERROR("Unknown exception caught when reading HLT bits");
     return StatusCode::FAILURE;
   }
-  resultToFill.setHltBits( {hltBitWords.begin(), hltBitWords.end()} );
+  if (hltBitWords.size() % 3 != 0) {
+    ATH_MSG_ERROR("Size of hltBitWords=" << hltBitWords.size() << " must be divisible by three. Expecting {raw, prescaled, rerun} bits.");
+    return StatusCode::FAILURE;
+  }
+  const size_t sizeOfBlock = hltBitWords.size() / 3;
+  auto beginPrescaledIt = hltBitWords.begin();
+  std::advance(beginPrescaledIt, sizeOfBlock);
+  auto beginRerunIt = hltBitWords.begin();
+  std::advance(beginRerunIt, 2 * sizeOfBlock);
+  resultToFill.setHltPassRawBits( {hltBitWords.begin(), beginPrescaledIt} );
+  resultToFill.setHltPrescaledBits( {beginPrescaledIt, beginRerunIt} );
+  resultToFill.setHltRerunBits( {beginRerunIt, hltBitWords.end()} );
   ATH_MSG_DEBUG("Successfully read " << hltBitWords.size() << " HLT bit words");
-
   return StatusCode::SUCCESS;
 }
 
diff --git a/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt b/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
index 00777f1e5f25a327c8511a74fb5e491b4d093b0b..fccacba023874db43d6f03d61e211a224a80d747 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
+++ b/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
@@ -21,15 +21,17 @@ atlas_depends_on_subdirs( PUBLIC
                           Trigger/TrigDataAccess/TrigSerializeResult
                           Event/xAOD/xAODTrigMuon
                           Event/xAOD/xAODMuon
-			  Event/xAOD/xAODTrigMissingET
-			  Event/xAOD/xAODTau
-			  Event/xAOD/xAODTrigBphys
+                          Event/xAOD/xAODTrigMissingET
+                          Event/xAOD/xAODTau
+                          Event/xAOD/xAODTrigBphys
                           Trigger/TrigSteer/DecisionHandling
                           Control/AthenaMonitoring
                           Trigger/TrigMonitoring/TrigCostMonitorMT
                           Trigger/TrigAlgorithms/TrigPartialEventBuilding
-			  Trigger/TrigDataAccess/TrigSerializeTP
-			  Control/AthContainersRoot
+                          Trigger/TrigDataAccess/TrigSerializeTP
+                          Trigger/TrigConfiguration/TrigConfData
+                          Trigger/TrigConfiguration/TrigConfIO
+                          Control/AthContainersRoot
                           )
 find_package( tdaq-common COMPONENTS eformat )
 find_package( Boost )
@@ -39,7 +41,7 @@ atlas_add_library( TrigOutputHandlingLib
                    src/*.cxx
                    PUBLIC_HEADERS TrigOutputHandling
                    INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS}
-                   LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES}  GaudiKernel AthViews AthenaBaseComps TrigSteeringEvent TrigSerializeResultLib
+                   LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES}  GaudiKernel AthViews AthenaBaseComps TrigSteeringEvent TrigSerializeResultLib TrigConfData TrigConfIOLib
                    xAODTrigCalo xAODTrigEgamma xAODTrigger xAODTracking xAODTrigMuon xAODMuon xAODTau xAODTrigBphys xAODTrigMissingET DecisionHandlingLib AthenaMonitoringLib TrigPartialEventBuildingLib TrigSerializeTPLib AthContainersRoot )
 
 atlas_add_component( TrigOutputHandling
diff --git a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
index c0df31d223e0cd25cf19705ffadf5889f961fdde..875f878fb08a3f291b74f54e7206687b75acb7db 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
@@ -26,14 +26,18 @@ public:
   virtual StatusCode finalize() override;
 
 private:
-  SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_finalChainDecisions { this, "ChainDecisions", "HLTNav_Summary", "Container with final chain decisions"  }; 
+  enum BitCategory{ HLTPassRawCategory, HLTPrescaledCategory, HLTRerunCategory };
 
-  Gaudi::Property<std::map<std::string, int>> m_chainToStreamProperty { this, "ChainToBit", {}, "Mapping from the chain name to bit position in trigger bits array"};
+  StatusCode setBit(const TrigCompositeUtils::DecisionID chain, const BitCategory category, HLT::HLTResultMT& resultToFill) const;
 
-  typedef std::map< TrigCompositeUtils::DecisionID, int> ChainToBitMap;
-  ChainToBitMap m_mapping;
+  SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_finalChainDecisions { this, "ChainDecisions", "HLTNav_Summary", "Container with final chain decisions"  };
 
+  Gaudi::Property<std::string> m_menuJSON {this, "HLTmenuFile", "UNSET", "Filename of just-generated HLT Menu JSON used to configure the TriggerBitsMakerTool"};
 
+  typedef std::map< TrigCompositeUtils::DecisionID, uint32_t> ChainToBitMap;
+  ChainToBitMap m_mapping; //!< Mapping of each chain's hash ID to its chain counter
+
+  uint32_t m_largestBit; //!< Largest chain counter hence largest bit needed to be stored in result bitmap
 };
 
 #endif // TRIGOUTPUTHANDLING_TRIGGERBITSMAKERTOOL_H
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
index ab709e020ff277e5497597af3bb97fa1389a0926..eb0e05cb4413231b92671f258339fc0a24a81299 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
@@ -149,7 +149,9 @@ StatusCode HLTResultMTMaker::makeResult(const EventContext& eventContext) const
 
   // Fill monitoring histograms
   auto nstreams = Monitored::Scalar("nstreams", hltResult->getStreamTags().size());
-  auto bitWords = Monitored::Scalar("bitWords", hltResult->getHltBits().size());
+  auto bitWords = Monitored::Scalar("bitWords", hltResult->getHltPassRawBits().size() 
+    + hltResult->getHltPrescaledBits().size()
+    + hltResult->getHltRerunBits().size() );
   auto nfrags   = Monitored::Scalar("nfrags",   hltResult->getSerialisedData().size());
   auto sizeMain = Monitored::Scalar("sizeMain", -1.);
   auto iter = hltResult->getSerialisedData().find(0); // this is the main fragment of the HLT result
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
index 9e03585539b211c92af889119939be4b27704578..73e9ebfba82f5e06a95a2b29b86c2705ec22a391 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
@@ -3,6 +3,10 @@
 */
 #include "DecisionHandling/HLTIdentifier.h"
 #include "TrigOutputHandling/TriggerBitsMakerTool.h"
+#include "TrigConfIO/JsonFileLoader.h"
+#include "TrigConfData/HLTMenu.h"
+
+#include <algorithm>
 
 TriggerBitsMakerTool::TriggerBitsMakerTool(const std::string& type, const std::string& name, const IInterface* parent) :
   base_class(type, name, parent){}
@@ -12,11 +16,16 @@ TriggerBitsMakerTool::~TriggerBitsMakerTool() {}
 StatusCode TriggerBitsMakerTool::initialize() {
   ATH_CHECK( m_finalChainDecisions.initialize() );
 
-  for ( auto& chainAndBit: m_chainToStreamProperty ) {
-    struct { std::string chain; int bit; } conf { chainAndBit.first, chainAndBit.second };    
-    ATH_MSG_DEBUG( "Chain " << conf.chain << " will flip  " << conf.bit <<  " bit" );
-    m_mapping[ HLT::Identifier( conf.chain ) ] = conf.bit;
-    
+  TrigConf::JsonFileLoader fileLoader;
+  TrigConf::HLTMenu hltmenu;
+  ATH_CHECK( fileLoader.loadFile(m_menuJSON, hltmenu) );
+  ATH_MSG_INFO("Configuring from " << m_menuJSON << " with " << hltmenu.size() << " chains");
+
+  m_largestBit = 0;
+  for(auto& ch : hltmenu) {
+    ATH_MSG_DEBUG( "Chain " << ch.name() << " will flip " << ch.counter() <<  " bit" );
+    m_mapping[ HLT::Identifier( ch.name() ) ] = ch.counter();
+    m_largestBit = std::max(m_largestBit, ch.counter());
   }
 
   return StatusCode::SUCCESS;
@@ -24,49 +33,85 @@ StatusCode TriggerBitsMakerTool::initialize() {
 
 
 StatusCode TriggerBitsMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
+
+  using namespace TrigCompositeUtils;
+
   auto chainsHandle = SG::makeHandle( m_finalChainDecisions );
   if (!chainsHandle.isValid()) {
     ATH_MSG_ERROR("Unable to read in the HLTNav_Summary from the DecisionSummaryMakerAlg");
     return StatusCode::FAILURE;
   }
 
-  const TrigCompositeUtils::Decision* passRawChains = nullptr;
-  for (const TrigCompositeUtils::Decision* d : *chainsHandle) {
-    if (d->name() == "HLTPassRaw") {
-      passRawChains = d;
+  const Decision* HLTPassRaw = nullptr;
+  const Decision* HLTPrescaled = nullptr;
+  const Decision* HLTRerun = nullptr;
+
+  DecisionIDContainer passRawIDs; //!< The chains which returned a positive decision
+  DecisionIDContainer prescaledIDs; //!< The chains which did not run due to being prescaled out
+  DecisionIDContainer rerunIDs; //!< The chains which were activate only in the rerun (not physics decisions)
+
+  // Read the sets of chain IDs
+  for (const Decision* decisionObject : *chainsHandle) {
+    // Collect all decisions (IDs of passed/prescaled/rerun chains) from named decisionObjects
+    if (decisionObject->name() == "HLTPassRaw") {
+      HLTPassRaw = decisionObject;
+    } else if (decisionObject->name() == "HLTPrescaled") {
+      HLTPrescaled = decisionObject;
+    } else if (decisionObject->name() == "HLTRerun") {
+      HLTRerun = decisionObject;
+    }
+    if (HLTPassRaw && HLTPrescaled && HLTRerun) {
       break;
     }
   }
 
-  if (passRawChains == nullptr) {
-    ATH_MSG_ERROR("Unable to read in the HLTNav_Summary from the DecisionSummaryMakerAlg");
-    return StatusCode::FAILURE;
-  }
+  ATH_CHECK(HLTPassRaw != nullptr);
+  ATH_CHECK(HLTPrescaled != nullptr);
+  ATH_CHECK(HLTRerun != nullptr);
 
-  TrigCompositeUtils::DecisionIDContainer passRawIDs;
-  TrigCompositeUtils::decisionIDs(passRawChains, passRawIDs);
+  decisionIDs(HLTPassRaw, passRawIDs);
+  decisionIDs(HLTPrescaled, prescaledIDs);
+  decisionIDs(HLTRerun, rerunIDs);
+
+  resultToFill.reserveHltBits( m_largestBit );
 
   for ( TrigCompositeUtils::DecisionID chain: passRawIDs ) {
-    auto mappingIter = m_mapping.find( chain );
-    // each chain has to have stream
-    if( mappingIter == m_mapping.end() ) { 
-      ATH_MSG_ERROR("Each chain has to have the bit/counter associated whereas the " << HLT::Identifier( chain ) << " does not" );
-      return StatusCode::FAILURE;
-    }
-    const int chainBitPosition = mappingIter->second;
-    ATH_MSG_DEBUG("Setting bit " << chainBitPosition << " corresponding to chain" << HLT::Identifier(chain));
-    ATH_CHECK(resultToFill.addHltBit(chainBitPosition));
+    ATH_CHECK(setBit(chain, HLTPassRawCategory, resultToFill));
+  }
+
+  for ( TrigCompositeUtils::DecisionID chain: prescaledIDs ) {
+    ATH_CHECK(setBit(chain, HLTPrescaledCategory, resultToFill));
+  }
+
+  for ( TrigCompositeUtils::DecisionID chain: rerunIDs ) {
+    ATH_CHECK(setBit(chain, HLTRerunCategory, resultToFill));
   }
 
   if ( msgLvl( MSG::DEBUG ) ) {
-    ATH_MSG_DEBUG("HLT result now has " << resultToFill.getHltBits().num_blocks() << " words with trigger bits:");
+    ATH_MSG_DEBUG("HLT result now has " << resultToFill.getHltBitsAsWords().size() << " words with trigger bits:");
     for (const auto& w : resultToFill.getHltBitsAsWords()) ATH_MSG_DEBUG("0x" << MSG::hex << w << MSG::dec);
   }
   return StatusCode::SUCCESS;
 
 }
 
-
+StatusCode TriggerBitsMakerTool::setBit(const TrigCompositeUtils::DecisionID chain, const BitCategory category, HLT::HLTResultMT& resultToFill) const {
+  auto mappingIter = m_mapping.find( chain );
+  // each chain has to have stream
+  if( mappingIter == m_mapping.end() ) {
+    ATH_MSG_ERROR("Each chain has to have the bit/counter associated whereas the " << HLT::Identifier( chain ) << " does not" );
+    return StatusCode::FAILURE;
+  }
+  const int chainBitPosition = mappingIter->second;
+  ATH_MSG_DEBUG("Setting bit " << chainBitPosition << " corresponding to chain" << HLT::Identifier(chain) << " in BitCategory " << category);
+  switch (category) {
+    case HLTPassRawCategory: ATH_CHECK(resultToFill.addHltPassRawBit(chainBitPosition)); break;
+    case HLTPrescaledCategory: ATH_CHECK(resultToFill.addHltPrescaledBit(chainBitPosition)); break;
+    case HLTRerunCategory: ATH_CHECK(resultToFill.addHltRerunBit(chainBitPosition)); break;
+    default: ATH_MSG_ERROR("Unknown BitCategory"); return StatusCode::FAILURE; break;
+  }
+  return StatusCode::SUCCESS;
+}
 
 StatusCode TriggerBitsMakerTool::finalize() {
   return StatusCode::SUCCESS;
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
index 8c4857c1d7872ac60d24a051992cb4e4db4f7c81..51a4b395a0ca40662f7c2a133cd43c1458947a24 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
@@ -221,10 +221,8 @@ def triggerBSOutputCfg( flags, decObj ):
     """
     acc = ComponentAccumulator()
 
-
-
     from TrigEDMConfig.TriggerEDMRun3 import TriggerHLTListRun3, persistent
-    from TrigOutputHandling.TrigOutputHandlingConf import HLTResultMTMakerAlg # , StreamTagMakerTool, TriggerBitsMakerTool     # TODO add config of these two
+    from TrigOutputHandling.TrigOutputHandlingConf import HLTResultMTMakerAlg, TriggerBitsMakerTool #, StreamTagMakerTool # TODO add config of this
     from TrigOutputHandling.TrigOutputHandlingConfig import TriggerEDMSerialiserToolCfg, HLTResultMTMakerCfg
     
     serialiser = TriggerEDMSerialiserToolCfg("Serialiser")
@@ -240,14 +238,14 @@ def triggerBSOutputCfg( flags, decObj ):
         __log.info( "Serialising {}".format( serialisedTypeColl ) ) 
         serialiser.addCollectionListToMainResult( [ serialisedTypeColl ] )
         
-        
-    # not configuring the two tools below now as we soon will change method to configure them (via TrigConfigSvc)
+    bitsmaker = TriggerBitsMakerTool()
+    bitsmaker.HLTmenuFile = flags.Trigger.HLTMenuJsonFile
+
+    # not configuring the tools below now as we soon will change method to configure them (via TrigConfigSvc)
     #stmaker                       = StreamTagMakerTool()
-    #bitsmaker                     = TriggerBitsMakerTool()
-    
     
     hltResultMakerTool            = HLTResultMTMakerCfg("MakerTool") # want short nme to see in the log
-    hltResultMakerTool.MakerTools = [ serialiser ] #, stmaker, bitsmaker ] 
+    hltResultMakerTool.MakerTools = [ serialiser, bitsmaker ] #, stmaker 
     hltResultMakerAlg             = HLTResultMTMakerAlg()
     hltResultMakerAlg.ResultMaker = hltResultMakerTool
     acc.addEventAlgo( hltResultMakerAlg )
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigFlags.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigFlags.py
index f7ec638e4c9e7c615ec78c8ee9c076fc0c7017cc..a17df65d23780701927da142135c148a1fe48258 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigFlags.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigFlags.py
@@ -97,10 +97,14 @@ def createTriggerFlags():
     # generate or not the HLT configuration
     flags.addFlag('Trigger.generateHLTConfig', False)
     
-    # HLT XML file name 
+    # HLT XML file name (R2 Legacy)
     flags.addFlag('Trigger.HLTConfigFile',
                 lambda prevFlags: 'HLTconfig_'+prevFlags.Trigger.triggerMenuSetup+'_' + prevFlags.Trigger.menuVersion + '.xml')
 
+    # HLT JSON file name (R3)
+    flags.addFlag('Trigger.HLTMenuJsonFile',
+                lambda prevFlags: 'HLTmenu_'+prevFlags.Trigger.triggerMenuSetup+'_' + prevFlags.Trigger.menuVersion + '.json')
+
     # generate or not the L1 configuration
     flags.addFlag('Trigger.generateLVL1Config', False)
     
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerFlags.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerFlags.py
index a3bc85ae5bb817f1a9175c582ca88c77aec0544d..6fef5dcdf9ba364c5370bc3a35d73b13721b84d1 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerFlags.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerFlags.py
@@ -887,7 +887,18 @@ class outputHLTconfigFile(JobProperty):
 
 _flags.append(outputHLTconfigFile)
 
+class outputHLTmenuJsonFile(JobProperty):
+    """ File name for output HLT configuration XML file """
+    statusOn=True
+    StoredValue=""
+
+    def __call__(self):
+        if self.get_Value() == "":
+            return "HLTmenu_"+TriggerFlags.triggerMenuSetup()+"_" + TriggerFlags.menuVersion() + ".json"
+        else:
+            return self.get_Value()
 
+_flags.append(outputHLTmenuFile)
 
 class inputL1TopoConfigFile(JobProperty):
     """Used to define an external L1Topo configuration file. To be
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTMenuJSON.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTMenuJSON.py
index 97052b250418c707dee42ccfd68847a34cc00ccc..f3699e3ba2950229dbae0e31e37c8574ab2fad25 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTMenuJSON.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTMenuJSON.py
@@ -5,7 +5,7 @@ from AthenaCommon.Logging import logging
 __log = logging.getLogger( 'HLTMenuJSON.py' )
 
 
-def __generateJSON( chainDicts, sequences, menuName ):
+def __generateJSON( chainDicts, sequences, menuName, fileName ):
     """ Generates JSON given the ChainProps and sequences
     """
     menuDict = { "name":menuName ,  "chains":[] }
@@ -28,9 +28,6 @@ def __generateJSON( chainDicts, sequences, menuName ):
         menuDict["chains"].append( chainDict )
         counter += 1
 
-    from AthenaCommon.AppMgr import release_metadata
-    fileName = "HLTmenu_%s_%s.json" % (menuName, release_metadata()['release'])
-
     __log.info( "Writing trigger menu to %s", fileName )
     with open( fileName, 'w' ) as fp:
         json.dump( menuDict, fp, indent=4, sort_keys=True )
@@ -41,7 +38,7 @@ def generateJSON( allStepsSequence ):
     from TriggerMenuMT.HLTMenuConfig.Menu.TriggerConfigHLT import TriggerConfigHLT
     triggerConfigHLT = TriggerConfigHLT.currentTriggerConfig()
 
-    return __generateJSON( triggerConfigHLT.allChainDicts, None, TriggerFlags.triggerMenuSetup() )
+    return __generateJSON( triggerConfigHLT.allChainDicts, None, TriggerFlags.triggerMenuSetup(), TriggerFlags.outputHLTmenuJsonFile() )
     
 def generateJSON_newJO( allStepsSequence ):
     __log.info("Generating HLT JSON config in the new JO")
@@ -57,4 +54,4 @@ def generateJSON_newJO( allStepsSequence ):
             for chain in ConfigFlags._get( name ):
                 chainDicts.append( decoder.getChainDict( chain ) )
                                     
-    return __generateJSON( chainDicts, None, ConfigFlags.Trigger.triggerMenuSetup )
+    return __generateJSON( chainDicts, None, ConfigFlags.Trigger.triggerMenuSetup, ConfigFlags.Trigger.HLTMenuJsonFile )