diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/R3MatchingTool.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/R3MatchingTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6ef34c6e8bbbe6f5cb3be83983c4258ed70a6720
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/R3MatchingTool.cxx
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TriggerMatchingTool/R3MatchingTool.h"
+#include "xAODBase/IParticleContainer.h"
+
+// Anonymous namespace for helper functions
+namespace
+{
+  // Helper function to efficiently decide if two objects are within a drThreshold of each other
+  bool fastDR(float eta1, float phi1, float eta2, float phi2, float drThreshold)
+  {
+    float dEta = eta1 - eta2;
+    if (dEta > drThreshold)
+      return false;
+    float dPhi = phi1 - phi2;
+    if (dPhi > drThreshold)
+      return false;
+    return dEta * dEta + dPhi * dPhi < drThreshold * drThreshold;
+  }
+} // namespace
+
+namespace Trig
+{
+
+  R3MatchingTool::R3MatchingTool(const std::string &name) : asg::AsgTool(name)
+  {
+    declareProperty("TrigDecisionTool", m_trigDecTool, "The trigger decision tool");
+  }
+
+  R3MatchingTool::~R3MatchingTool() {}
+
+  StatusCode R3MatchingTool::initialize()
+  {
+    ATH_CHECK(m_trigDecTool.retrieve());
+    return StatusCode::SUCCESS;
+  }
+
+  bool R3MatchingTool::match(
+      const std::vector<const xAOD::IParticle *> &recoObjects,
+      const std::string &chain,
+      double matchThreshold,
+      bool rerun) const
+  {
+    if (recoObjects.size() == 0)
+      // If there are no reco objects, the matching is trivially true
+      return true;
+    // Make the LinkInfo type less verbose
+    using IPartLinkInfo_t = TrigCompositeUtils::LinkInfo<xAOD::IParticleContainer>;
+    // TODO - detect if we're looking at run 3 data.
+    // If we are, then setting rerun to true should give a warning as it no
+    // longer makes sense for run 3
+    if (recoObjects.size() != 1)
+    {
+      ATH_MSG_WARNING("Matching of multiple objects is not yet supported!");
+      return false;
+    }
+    // This has to assume that the last IParticle feature in each chain is the
+    // correct one - I don't *think* this will cause any issues.
+    // Unlike with TEs, each chain should build in nodes that it actually uses.
+    // This means that we don't need anything clever for the etcut triggers any more (for example)
+    std::vector<IPartLinkInfo_t> features = m_trigDecTool->features<xAOD::IParticleContainer>(
+        chain,
+        rerun ? TrigDefs::Physics | TrigDefs::allowResurrectedDecision : TrigDefs::Physics);
+    ATH_MSG_DEBUG("Found " << features.size() << " features for chain group " << chain);
+    // TODO:
+    //  Right now we are only looking at single object chains, so we only need
+    //  to find a single match for one reco-object.
+    //  Longer term we need to deal with combinations so this gets harder
+    const xAOD::IParticle &recoObject = *recoObjects.at(0);
+    for (const IPartLinkInfo_t &info : features)
+    {
+      if (!info.link.isValid())
+      {
+        // This could result in false negatives...
+        ATH_MSG_WARNING("Invalid link to trigger feature for chain " << chain);
+        continue;
+      }
+      const xAOD::IParticle &trigObject = **info.link;
+      if (fastDR(
+              recoObject.eta(),
+              recoObject.phi(),
+              trigObject.eta(),
+              trigObject.phi(),
+              matchThreshold))
+        // Once we find one match, that is enough
+        return true;
+    }
+    // If we get here then there was no good match
+    return false;
+  }
+
+  bool R3MatchingTool::match(
+      const xAOD::IParticle &recoObject,
+      const std::string &chain,
+      double matchThreshold,
+      bool rerun) const
+  {
+    std::vector<const xAOD::IParticle *> tmpVec{&recoObject};
+    return match(tmpVec, chain, matchThreshold, rerun);
+  }
+
+} // namespace Trig
\ No newline at end of file
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/R3MatchingTool.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/R3MatchingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..00ee2d004b3b948cbaaef29fa508342ee057b4de
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/R3MatchingTool.h
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_R3MATCHINGTOOL_H
+#define TRIGGERMATCHINGTOOL_R3MATCHINGTOOL_H
+
+#include "AsgTools/AsgTool.h"
+#include "AsgTools/ToolHandle.h"
+#include "TriggerMatchingTool/IMatchingTool.h"
+#include "TrigDecisionTool/TrigDecisionTool.h"
+
+namespace Trig
+{
+  class R3MatchingTool : public asg::AsgTool, virtual public IMatchingTool
+  {
+    ASG_TOOL_CLASS(R3MatchingTool, IMatchingTool)
+  public:
+    R3MatchingTool(const std::string &name);
+    ~R3MatchingTool();
+
+    virtual StatusCode initialize() override;
+
+    virtual bool match(
+        const std::vector<const xAOD::IParticle *> &recoObjects,
+        const std::string &chain,
+        double matchThreshold,
+        bool rerun) const override;
+
+    virtual bool match(
+        const xAOD::IParticle &recoObject,
+        const std::string &chain,
+        double matchThreshold,
+        bool rerun) const override;
+
+  private:
+    ToolHandle<TrigDecisionTool> m_trigDecTool;
+  }; //> end class R3MatchingTool
+} // namespace Trig
+
+#endif //> !TRIGGERMATCHINGTOOL_R3MATCHINGTOOL_H
\ No newline at end of file
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml
index 4ceaff3c5b61c7daed88d9f76a51de9f385ba820..6dedd615f8c53e7ecee52b4fa4b60f93cb0fe7b4 100644
--- a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml
@@ -5,4 +5,5 @@
    <class name="Trig::IIParticleRetrievalTool" />
    <class name="Trig::IParticleRetrievalTool" />
    <class name="Trig::MatchFromCompositeTool" />
+   <class name="Trig::R3MatchingTool" />
 </lcgdict>
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx
index 83133a91681f2f26aebdd260588092cc04f456cf..c69aaf8cdc3910adae2604c43dac3ce4e2577ab5 100644
--- a/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx
@@ -1,14 +1,14 @@
 #include "TriggerMatchingTool/MatchingTool.h"
 #include "TriggerMatchingTool/IParticleRetrievalTool.h"
 #include "TriggerMatchingTool/MatchFromCompositeTool.h"
+#include "TriggerMatchingTool/R3MatchingTool.h"
 
-DECLARE_COMPONENT( Trig::MatchingTool )
+DECLARE_COMPONENT(Trig::MatchingTool)
 
-
-DECLARE_COMPONENT( Trig::MatchingTool )
-DECLARE_COMPONENT( Trig::IParticleRetrievalTool )
-DECLARE_COMPONENT( Trig::MatchFromCompositeTool )
+DECLARE_COMPONENT(Trig::MatchingTool)
+DECLARE_COMPONENT(Trig::IParticleRetrievalTool)
+DECLARE_COMPONENT(Trig::MatchFromCompositeTool)
+DECLARE_COMPONENT(Trig::R3MatchingTool)
 
 #include "../TestMatchingToolAlg.h"
-DECLARE_COMPONENT( TestMatchingToolAlg )
-
+DECLARE_COMPONENT(TestMatchingToolAlg)