diff --git a/src/developer/debug/debug_agent/breakpoint.cc b/src/developer/debug/debug_agent/breakpoint.cc
index e022d3b272d411838285b6e5cd474378a279adb8..b405c80c3242123e686f0689272da166ce71ec21 100644
--- a/src/developer/debug/debug_agent/breakpoint.cc
+++ b/src/developer/debug/debug_agent/breakpoint.cc
@@ -30,10 +30,16 @@ Breakpoint::~Breakpoint() {
 }
 
 zx_status_t Breakpoint::SetSettings(
+    debug_ipc::BreakpointType type,
     const debug_ipc::BreakpointSettings& settings) {
-  zx_status_t result = ZX_OK;
+  FXL_DCHECK(type == debug_ipc::BreakpointType::kSoftware ||
+             type == debug_ipc::BreakpointType::kHardware)
+      << "Got: " << debug_ipc::BreakpointTypeToString(type);
+  type_ = type;
   settings_ = settings;
 
+  zx_status_t result = ZX_OK;
+
   // The stats needs to reference the current ID. We assume setting the
   // settings doesn't update the stats (an option to do this may need to be
   // added in the future).
@@ -64,8 +70,6 @@ zx_status_t Breakpoint::SetSettings(
   return result;
 }
 
-
-
 bool Breakpoint::AppliesToThread(zx_koid_t pid,
                                  zx_koid_t tid) const {
   for (auto& location : settings_.locations) {
diff --git a/src/developer/debug/debug_agent/breakpoint.h b/src/developer/debug/debug_agent/breakpoint.h
index 81969691e4ee568324881e7bf39efbd0e14d0586..8e45d59ec70a0e43d06e2c0889cd3b106ac15cfc 100644
--- a/src/developer/debug/debug_agent/breakpoint.h
+++ b/src/developer/debug/debug_agent/breakpoint.h
@@ -57,7 +57,14 @@ class Breakpoint {
   const debug_ipc::BreakpointStats& stats() const { return stats_; }
 
   // Sets the initial settings, or updates settings.
-  zx_status_t SetSettings(const debug_ipc::BreakpointSettings& settings);
+  zx_status_t SetSettings(debug_ipc::BreakpointType,
+                          const debug_ipc::BreakpointSettings& settings);
+
+  debug_ipc::BreakpointType type() const { return type_; }
+
+  // The setter is used mostly for testing. Normal setting should go through
+  // SetSettings.
+  void set_type(debug_ipc::BreakpointType type) { type_ = type; }
   const debug_ipc::BreakpointSettings& settings() const { return settings_; }
 
   // A breakpoint can be set to apply to a specific set of threads. A thread
@@ -73,6 +80,7 @@ class Breakpoint {
 
   ProcessDelegate* process_delegate_;  // Non-owning.
 
+  debug_ipc::BreakpointType type_ = debug_ipc::BreakpointType::kLast;
   debug_ipc::BreakpointSettings settings_;
 
   debug_ipc::BreakpointStats stats_;
diff --git a/src/developer/debug/debug_agent/breakpoint_unittest.cc b/src/developer/debug/debug_agent/breakpoint_unittest.cc
index cfa2840e855385ab86f0455a5a48bf2f0bab5bdc..d2dc605846fd3535117a03100c330109a8d2b380 100644
--- a/src/developer/debug/debug_agent/breakpoint_unittest.cc
+++ b/src/developer/debug/debug_agent/breakpoint_unittest.cc
@@ -55,7 +55,8 @@ TEST(Breakpoint, Registration) {
   pr_settings.address = kAddress1;
 
   // Apply the settings.
-  ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp.SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                  settings));
   EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
             delegate.register_calls());
   EXPECT_TRUE(delegate.unregister_calls().empty());
@@ -69,7 +70,8 @@ TEST(Breakpoint, Registration) {
   pr_settings.thread_koid = 0;
   pr_settings.address = kAddress2;
 
-  ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp.SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                  settings));
   EXPECT_EQ(CallVector({CallPair{kProcess2, kAddress2}}),
             delegate.register_calls());
   EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
@@ -96,7 +98,8 @@ TEST(Breakpoint, Registration) {
   settings.locations.push_back(old_pr_settings);
   settings.locations.push_back(new_pr_settings);
 
-  ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp.SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                  settings));
 
   EXPECT_EQ(CallVector({{kProcess1, kAddress1}, {kProcess3, kAddress3}}),
             delegate.register_calls());
@@ -121,7 +124,8 @@ TEST(Breakpoint, Destructor) {
   pr_settings.address = kAddress1;
 
   // Apply the settings.
-  ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp->SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                   settings));
   EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
             delegate.register_calls());
   EXPECT_TRUE(delegate.unregister_calls().empty());
@@ -153,7 +157,8 @@ TEST(Breakpoint, HitCount) {
   pr_settings.address = kAddress1;
 
   // Apply the settings.
-  ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp->SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                   settings));
   delegate.Clear();
 
   EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
@@ -189,7 +194,8 @@ TEST(Breakpoint, OneShot) {
   pr_settings.address = kAddress;
 
   // Apply the settings.
-  ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
+  ASSERT_EQ(ZX_OK, bp->SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                   settings));
   delegate.Clear();
 
   EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
diff --git a/src/developer/debug/debug_agent/debug_agent.cc b/src/developer/debug/debug_agent/debug_agent.cc
index 1f67aad3f17b07b20bd9621b09f23985ea67a834..ad439a63ab6358ef98a69011854bb2deb4918dc2 100644
--- a/src/developer/debug/debug_agent/debug_agent.cc
+++ b/src/developer/debug/debug_agent/debug_agent.cc
@@ -346,17 +346,18 @@ void DebugAgent::OnWriteRegisters(
 void DebugAgent::OnAddOrChangeBreakpoint(
     const debug_ipc::AddOrChangeBreakpointRequest& request,
     debug_ipc::AddOrChangeBreakpointReply* reply) {
-  TIME_BLOCK();
-  uint32_t id = request.breakpoint.breakpoint_id;
 
-  auto found = breakpoints_.find(id);
-  if (found == breakpoints_.end()) {
-    found = breakpoints_
-                .emplace(std::piecewise_construct, std::forward_as_tuple(id),
-                         std::forward_as_tuple(this))
-                .first;
+  switch (request.breakpoint_type) {
+    case debug_ipc::BreakpointType::kSoftware:
+    case debug_ipc::BreakpointType::kHardware:
+      return SetupBreakpoint(request, reply);
+    case debug_ipc::BreakpointType::kWatchpoint:
+      return SetupWatchpoint(request, reply);
+    case debug_ipc::BreakpointType::kLast:
+      break;
   }
-  reply->status = found->second.SetSettings(request.breakpoint);
+
+  FXL_NOTREACHED() << "Invalid Breakpoint Type.";
 }
 
 void DebugAgent::OnRemoveBreakpoint(
@@ -418,6 +419,21 @@ void DebugAgent::UnregisterBreakpoint(Breakpoint* bp, zx_koid_t process_koid,
     proc->UnregisterBreakpoint(bp, address);
 }
 
+void DebugAgent::SetupBreakpoint(
+    const debug_ipc::AddOrChangeBreakpointRequest& request,
+    debug_ipc::AddOrChangeBreakpointReply* reply) {
+  uint32_t id = request.breakpoint.breakpoint_id;
+  auto found = breakpoints_.find(id);
+  if (found == breakpoints_.end()) {
+    found = breakpoints_
+                .emplace(std::piecewise_construct, std::forward_as_tuple(id),
+                         std::forward_as_tuple(this))
+                .first;
+  }
+  reply->status = found->second.SetSettings(request.breakpoint_type,
+                                            request.breakpoint);
+}
+
 zx_status_t DebugAgent::RegisterWatchpoint(
     Watchpoint* wp, zx_koid_t process_koid,
     const debug_ipc::AddressRange& range) {
@@ -442,6 +458,21 @@ void DebugAgent::UnregisterWatchpoint(Watchpoint* wp, zx_koid_t process_koid,
   process->UnregisterWatchpoint(wp, range);
 }
 
+void DebugAgent::SetupWatchpoint(
+    const debug_ipc::AddOrChangeBreakpointRequest& request,
+    debug_ipc::AddOrChangeBreakpointReply* reply) {
+  auto id = request.watchpoint.watchpoint_id;
+
+  auto wp_it = watchpoints_.find(id);
+  if (wp_it == watchpoints_.end()) {
+    wp_it = watchpoints_
+                .emplace(std::piecewise_construct, std::forward_as_tuple(id),
+                         std::forward_as_tuple(this))
+                .first;
+  }
+  reply->status = wp_it->second.SetSettings(request.watchpoint);
+}
+
 void DebugAgent::OnAddressSpace(const debug_ipc::AddressSpaceRequest& request,
                                 debug_ipc::AddressSpaceReply* reply) {
   TIME_BLOCK();
diff --git a/src/developer/debug/debug_agent/debug_agent.h b/src/developer/debug/debug_agent/debug_agent.h
index 2aad02405bb7caaca077c8f3c9e952d525e98de9..dbe5f7e935a95387d4efc0fec8152224f6ce6324 100644
--- a/src/developer/debug/debug_agent/debug_agent.h
+++ b/src/developer/debug/debug_agent/debug_agent.h
@@ -110,6 +110,9 @@ class DebugAgent : public RemoteAPI,
   void UnregisterBreakpoint(Breakpoint* bp, zx_koid_t process_koid,
                             uint64_t address) override;
 
+  void SetupBreakpoint(const debug_ipc::AddOrChangeBreakpointRequest& request,
+                       debug_ipc::AddOrChangeBreakpointReply* reply);
+
   // Watchpoint::ProcessDelegate implementation --------------------------------
 
   zx_status_t RegisterWatchpoint(Watchpoint*, zx_koid_t process_koid,
@@ -117,6 +120,9 @@ class DebugAgent : public RemoteAPI,
   void UnregisterWatchpoint(Watchpoint*, zx_koid_t process_koid,
                             const debug_ipc::AddressRange&) override;
 
+  void SetupWatchpoint(const debug_ipc::AddOrChangeBreakpointRequest& request,
+                       debug_ipc::AddOrChangeBreakpointReply* reply);
+
   // Job/Process/Thread Management ---------------------------------------------
 
   zx_status_t AddDebuggedJob(zx_koid_t job_koid, zx::job zx_job);
diff --git a/src/developer/debug/debug_agent/hardware_breakpoint.cc b/src/developer/debug/debug_agent/hardware_breakpoint.cc
index ab7aa3341eefbd4b2b343bfaad24d911c6252724..64bce53cf8dbf0d057d5613333e28cd6c6a63a26 100644
--- a/src/developer/debug/debug_agent/hardware_breakpoint.cc
+++ b/src/developer/debug/debug_agent/hardware_breakpoint.cc
@@ -169,7 +169,7 @@ std::set<zx_koid_t> HWThreadsTargeted(const ProcessBreakpoint& pb) {
   bool all_threads = false;
   for (Breakpoint* bp : pb.breakpoints()) {
     // We only care about hardware breakpoints.
-    if (bp->settings().type != debug_ipc::BreakpointType::kHardware)
+    if (bp->type() != debug_ipc::BreakpointType::kHardware)
       continue;
 
     for (auto& location : bp->settings().locations) {
diff --git a/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc b/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc
index 1a70af13c6e5c88808a2209961975210360c85b8..3ff19b18f68aaab229e0951a221c7f48ccac6b24 100644
--- a/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc
+++ b/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc
@@ -254,9 +254,9 @@ TEST(BreakpointIntegration, HWBreakpoint) {
     location.address = module_function;
 
     debug_ipc::AddOrChangeBreakpointRequest breakpoint_request = {};
+    breakpoint_request.breakpoint_type = debug_ipc::BreakpointType::kHardware;
     breakpoint_request.breakpoint.breakpoint_id = kBreakpointId;
     breakpoint_request.breakpoint.one_shot = true;
-    breakpoint_request.breakpoint.type = debug_ipc::BreakpointType::kHardware;
     breakpoint_request.breakpoint.locations.push_back(location);
     debug_ipc::AddOrChangeBreakpointReply breakpoint_reply;
     remote_api->OnAddOrChangeBreakpoint(breakpoint_request, &breakpoint_reply);
diff --git a/src/developer/debug/debug_agent/integration_tests/debugged_job_test.cc b/src/developer/debug/debug_agent/integration_tests/debugged_job_test.cc
index ab8e538139d3aa96e0279a8fe2011fcda9139e63..85a0aa681eba4a3a27bd16017760b8a005eae5bc 100644
--- a/src/developer/debug/debug_agent/integration_tests/debugged_job_test.cc
+++ b/src/developer/debug/debug_agent/integration_tests/debugged_job_test.cc
@@ -356,8 +356,8 @@ TEST(DebuggedJobIntegrationTest, DISABLED_RepresentativeScenario) {
   location.process_koid = process_koid;
   location.address = function_address;
   AddOrChangeBreakpointRequest breakpoint_request;
+  breakpoint_request.breakpoint_type = debug_ipc::BreakpointType::kSoftware;
   breakpoint_request.breakpoint.breakpoint_id = breakpoint_id;
-  breakpoint_request.breakpoint.type = debug_ipc::BreakpointType::kSoftware;
   breakpoint_request.breakpoint.locations.push_back(location);
   AddOrChangeBreakpointReply breakpoint_reply;
   remote_api->OnAddOrChangeBreakpoint(breakpoint_request, &breakpoint_reply);
diff --git a/src/developer/debug/debug_agent/process_breakpoint.cc b/src/developer/debug/debug_agent/process_breakpoint.cc
index 212d11c86b8058d2d879574577ac3139133ad120..0277274ccc6b3634302840843a1b1b05a76dc8f8 100644
--- a/src/developer/debug/debug_agent/process_breakpoint.cc
+++ b/src/developer/debug/debug_agent/process_breakpoint.cc
@@ -73,7 +73,7 @@ void ProcessBreakpoint::OnHit(
   hit_breakpoints->clear();
   for (Breakpoint* breakpoint : breakpoints_) {
     // Only care for breakpoints that match the exception type.
-    if (breakpoint->settings().type != exception_type)
+    if (breakpoint->type() != exception_type)
       continue;
 
     breakpoint->OnHit();
@@ -137,7 +137,7 @@ zx_status_t ProcessBreakpoint::Update() {
   // regardless of which threads are targeted.
   int sw_bp_count = 0;
   for (Breakpoint* bp : breakpoints_) {
-    if (bp->settings().type == debug_ipc::BreakpointType::kSoftware)
+    if (bp->type() == debug_ipc::BreakpointType::kSoftware)
       sw_bp_count++;
   }
 
diff --git a/src/developer/debug/debug_agent/process_breakpoint_unittest.cc b/src/developer/debug/debug_agent/process_breakpoint_unittest.cc
index 6da0d342383a6fbee5bd5cbb3c4142df07be2d40..9ba3a9de7d1b571936b634694a387b5c3f73e4c7 100644
--- a/src/developer/debug/debug_agent/process_breakpoint_unittest.cc
+++ b/src/developer/debug/debug_agent/process_breakpoint_unittest.cc
@@ -152,6 +152,7 @@ const char
 TEST(ProcessBreakpoint, InstallAndFixup) {
   TestProcessDelegate process_delegate;
   Breakpoint main_breakpoint(&process_delegate);
+  main_breakpoint.set_type(debug_ipc::BreakpointType::kSoftware);
   zx_koid_t process_koid = 0x1234;
   MockProcess process(process_koid);
 
@@ -188,6 +189,7 @@ TEST(ProcessBreakpoint, InstallAndFixup) {
 TEST(ProcessBreakpoint, StepMultiple) {
   TestProcessDelegate process_delegate;
   Breakpoint main_breakpoint(&process_delegate);
+  main_breakpoint.set_type(debug_ipc::BreakpointType::kSoftware);
 
   zx_koid_t process_koid = 0x1234;
   MockProcess process(process_koid);
@@ -245,14 +247,16 @@ TEST(ProcessBreakpoint, HitCount) {
   // (corresponds to two logical breakpoints at the same address).
   std::unique_ptr<Breakpoint> main_breakpoint1 =
       std::make_unique<Breakpoint>(&process_delegate);
-  zx_status_t status = main_breakpoint1->SetSettings(settings);
+  zx_status_t status = main_breakpoint1->SetSettings(
+      debug_ipc::BreakpointType::kSoftware, settings);
   ASSERT_EQ(ZX_OK, status);
 
   std::unique_ptr<Breakpoint> main_breakpoint2 =
       std::make_unique<Breakpoint>(&process_delegate);
   constexpr uint32_t kBreakpointId2 = 13;
   settings.breakpoint_id = kBreakpointId2;
-  status = main_breakpoint2->SetSettings(settings);
+  status = main_breakpoint2->SetSettings(debug_ipc::BreakpointType::kSoftware,
+                                         settings);
   ASSERT_EQ(ZX_OK, status);
 
   // There should only be one address with a breakpoint.
@@ -307,10 +311,10 @@ TEST(ProcessBreakpoint, HWBreakpointForAllThreads) {
   auto breakpoint = std::make_unique<Breakpoint>(&process_delegate);
   debug_ipc::BreakpointSettings settings1 = {};
   settings1.breakpoint_id = kBreakpointId1;
-  settings1.type = debug_ipc::BreakpointType::kHardware;
   // This location is for all threads.
   settings1.locations.push_back({kProcessId, 0, kAddress});
-  zx_status_t status = breakpoint->SetSettings(settings1);
+  zx_status_t status =
+      breakpoint->SetSettings(debug_ipc::BreakpointType::kHardware, settings1);
   ASSERT_EQ(status, ZX_OK);
 
   // Should have installed the breakpoint.
@@ -354,9 +358,9 @@ TEST(ProcessBreakpoint, HWBreakpointWithThreadId) {
   auto breakpoint1 = std::make_unique<Breakpoint>(&process_delegate);
   debug_ipc::BreakpointSettings settings1 = {};
   settings1.breakpoint_id = kBreakpointId1;
-  settings1.type = debug_ipc::BreakpointType::kHardware;
   settings1.locations.push_back({kProcessId, kThreadId1, kAddress});
-  zx_status_t status = breakpoint1->SetSettings(settings1);
+  zx_status_t status =
+      breakpoint1->SetSettings(debug_ipc::BreakpointType::kHardware, settings1);
   ASSERT_EQ(status, ZX_OK);
   // Should have installed the process breakpoint.
   ASSERT_EQ(process_delegate.bps().size(), 1u);
@@ -374,13 +378,12 @@ TEST(ProcessBreakpoint, HWBreakpointWithThreadId) {
   auto breakpoint2 = std::make_unique<Breakpoint>(&process_delegate);
   debug_ipc::BreakpointSettings settings2 = {};
   settings2.breakpoint_id = kBreakpointId2;
-  settings2.type = debug_ipc::BreakpointType::kHardware;
   settings2.locations.push_back({kProcessId, kThreadId2, kAddress});
   // This breakpoint has another location for another thread.
   // In practice, this should not happen, but it's important that no HW
   // breakpoint get installed if for the wrong location.
   settings2.locations.push_back({kProcessId, kThreadId3, kOtherAddress});
-  breakpoint2->SetSettings(settings2);
+  breakpoint2->SetSettings(debug_ipc::BreakpointType::kHardware, settings2);
   // Registering this breakpoint should create a new ProcessBreakpoint.
   ASSERT_EQ(process_delegate.bps().size(), 2u);
   auto& process_bp2 = (process_delegate.bps().begin()++)->second;
@@ -409,9 +412,8 @@ TEST(ProcessBreakpoint, HWBreakpointWithThreadId) {
   auto sw_breakpoint = std::make_unique<Breakpoint>(&process_delegate);
   debug_ipc::BreakpointSettings sw_settings = {};
   sw_settings.breakpoint_id = kSwBreakpointId;
-  sw_settings.type = debug_ipc::BreakpointType::kSoftware;
   sw_settings.locations.push_back({kProcessId, 0, kAddress});
-  sw_breakpoint->SetSettings(sw_settings);
+  sw_breakpoint->SetSettings(debug_ipc::BreakpointType::kSoftware, sw_settings);
   // Should have installed only a SW breakpoint.
   ASSERT_EQ(arch_provider->TotalBreakpointInstallCalls(), 3u);
   ASSERT_EQ(arch_provider->TotalBreakpointUninstallCalls(), 1u);
diff --git a/src/developer/debug/ipc/agent_protocol.cc b/src/developer/debug/ipc/agent_protocol.cc
index 08896f0a6960c55dca9f42c4e3c02af6d56eb12b..e4c4543d984fdb211d754bad02bf93d8c5b2694d 100644
--- a/src/developer/debug/ipc/agent_protocol.cc
+++ b/src/developer/debug/ipc/agent_protocol.cc
@@ -31,11 +31,6 @@ bool Deserialize(MessageReader* reader, BreakpointSettings* settings) {
     return false;
   settings->stop = static_cast<Stop>(stop);
 
-  uint32_t type;
-  if (!reader->ReadUint32(&type))
-    return false;
-  settings->type = static_cast<BreakpointType>(type);
-
   return Deserialize(reader, &settings->locations);
 }
 
@@ -350,6 +345,14 @@ bool ReadRequest(MessageReader* reader, AddOrChangeBreakpointRequest* request,
   if (!reader->ReadHeader(&header))
     return false;
   *transaction_id = header.transaction_id;
+
+  uint32_t breakpoint_type;
+  if (!reader->ReadUint32(&breakpoint_type) ||
+      breakpoint_type >= static_cast<uint32_t>(BreakpointType::kLast)) {
+    return false;
+  }
+  request->breakpoint_type = static_cast<BreakpointType>(breakpoint_type);
+
   return Deserialize(reader, &request->breakpoint);
 }
 
diff --git a/src/developer/debug/ipc/client_protocol.cc b/src/developer/debug/ipc/client_protocol.cc
index 22deddfc4a7e3af6a07198be5227848389826026..20d6544e0089fb2c9d0da0c6a8e48a45a64f038c 100644
--- a/src/developer/debug/ipc/client_protocol.cc
+++ b/src/developer/debug/ipc/client_protocol.cc
@@ -130,7 +130,6 @@ void Serialize(const BreakpointSettings& settings, MessageWriter* writer) {
   writer->WriteUint32(settings.breakpoint_id);
   writer->WriteBool(settings.one_shot);
   writer->WriteUint32(static_cast<uint32_t>(settings.stop));
-  writer->WriteUint32(static_cast<uint32_t>(settings.type));
   Serialize(settings.locations, writer);
 }
 
@@ -414,6 +413,7 @@ bool ReadReply(MessageReader* reader, WriteRegistersReply* reply,
 void WriteRequest(const AddOrChangeBreakpointRequest& request,
                   uint32_t transaction_id, MessageWriter* writer) {
   writer->WriteHeader(MsgHeader::Type::kAddOrChangeBreakpoint, transaction_id);
+  writer->WriteUint32(static_cast<uint32_t>(request.breakpoint_type));
   Serialize(request.breakpoint, writer);
 }
 
diff --git a/src/developer/debug/ipc/protocol.h b/src/developer/debug/ipc/protocol.h
index 8912de60183b8ec88d56e636c539b77ae502bc4d..a72b7539b178c848837cbce3513d247b2f20c7e6 100644
--- a/src/developer/debug/ipc/protocol.h
+++ b/src/developer/debug/ipc/protocol.h
@@ -222,7 +222,12 @@ struct ReadMemoryReply {
 };
 
 struct AddOrChangeBreakpointRequest {
+  // What kind of request this is.
+  BreakpointType breakpoint_type = BreakpointType::kSoftware;
+
+  // Only one of these should be valid at a time.
   BreakpointSettings breakpoint;
+  WatchpointSettings watchpoint;
 };
 struct AddOrChangeBreakpointReply {
   // A variety of race conditions could cause a breakpoint modification or
diff --git a/src/developer/debug/ipc/protocol_unittests.cc b/src/developer/debug/ipc/protocol_unittests.cc
index 09e8abca3bd5543a735465689a51bd7273839d70..07f715fe65a722ab7da34284be0310a94fd7e4f8 100644
--- a/src/developer/debug/ipc/protocol_unittests.cc
+++ b/src/developer/debug/ipc/protocol_unittests.cc
@@ -379,6 +379,7 @@ TEST(Protocol, ReadMemoryReply) {
 
 TEST(Protocol, AddOrChangeBreakpointRequest) {
   AddOrChangeBreakpointRequest initial;
+  initial.breakpoint_type = BreakpointType::kHardware;
   initial.breakpoint.breakpoint_id = 8976;
   initial.breakpoint.stop = debug_ipc::Stop::kProcess;
   initial.breakpoint.locations.resize(1);
@@ -391,6 +392,7 @@ TEST(Protocol, AddOrChangeBreakpointRequest) {
   AddOrChangeBreakpointRequest second;
   ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
 
+  EXPECT_EQ(initial.breakpoint_type, second.breakpoint_type);
   EXPECT_EQ(initial.breakpoint.breakpoint_id, second.breakpoint.breakpoint_id);
   EXPECT_EQ(initial.breakpoint.stop, second.breakpoint.stop);
   ASSERT_EQ(initial.breakpoint.locations.size(),
diff --git a/src/developer/debug/ipc/records.cc b/src/developer/debug/ipc/records.cc
index 0659ad7e4b87b497054418ee34b84be141f13100..935435566a173c5fde41fd0e4a6e2dbc359ab408 100644
--- a/src/developer/debug/ipc/records.cc
+++ b/src/developer/debug/ipc/records.cc
@@ -77,6 +77,22 @@ const char* RegisterCategory::TypeToString(RegisterCategory::Type type) {
   return nullptr;
 }
 
+const char* BreakpointTypeToString(BreakpointType type) {
+  switch (type) {
+    case BreakpointType::kSoftware:
+      return "Software";
+    case BreakpointType::kHardware:
+      return "Hardware";
+    case BreakpointType::kWatchpoint:
+      return "Watchpoint";
+    case BreakpointType::kLast:
+      return "Last";
+  }
+
+  FXL_NOTREACHED();
+  return nullptr;
+}
+
 RegisterCategory::Type RegisterCategory::RegisterIDToCategory(RegisterID id) {
   uint32_t val = static_cast<uint32_t>(id);
 
diff --git a/src/developer/debug/ipc/records.h b/src/developer/debug/ipc/records.h
index 835719274c49858cdf0bacfb2464e35c50822849..143803ef0d5819827cb0a9972e5fd79cd153f32f 100644
--- a/src/developer/debug/ipc/records.h
+++ b/src/developer/debug/ipc/records.h
@@ -151,7 +151,10 @@ enum class Stop : uint32_t {
 enum class BreakpointType : uint32_t {
   kSoftware,
   kHardware,
+  kWatchpoint,
+  kLast,
 };
+const char* BreakpointTypeToString(BreakpointType);
 
 struct BreakpointSettings {
   // The ID if this breakpoint. This is assigned by the client. This is
@@ -166,9 +169,6 @@ struct BreakpointSettings {
   // What should stop when the breakpoint is hit.
   Stop stop = Stop::kAll;
 
-  // What kind of breakpoint this is.
-  BreakpointType type = BreakpointType::kSoftware;
-
   // Processes to which this breakpoint applies.
   //
   // If any process specifies a nonzero thread_koid, it must be the only
diff --git a/src/developer/debug/zxdb/client/breakpoint_impl.cc b/src/developer/debug/zxdb/client/breakpoint_impl.cc
index 1e040054fe24492eed0f21e041ab680e99f3a889..5958015b2f6c6f55c53308a30a84316defa1b8c7 100644
--- a/src/developer/debug/zxdb/client/breakpoint_impl.cc
+++ b/src/developer/debug/zxdb/client/breakpoint_impl.cc
@@ -260,10 +260,10 @@ void BreakpointImpl::SendBackendAddOrChange(
   backend_installed_ = true;
 
   debug_ipc::AddOrChangeBreakpointRequest request;
+  request.breakpoint_type = settings_.type;
   request.breakpoint.breakpoint_id = backend_id_;
   request.breakpoint.stop = SettingsStopToIpcStop(settings_.stop_mode);
   request.breakpoint.one_shot = settings_.one_shot;
-  request.breakpoint.type = settings_.type;
 
   for (const auto& proc : procs_) {
     for (const auto& pair : proc.second.locs) {
diff --git a/src/developer/debug/zxdb/console/command_utils.cc b/src/developer/debug/zxdb/console/command_utils.cc
index dd3dfe80ed42aae3be9c597e154e1047889ae26d..e0319e4eb6a309061472ac9d17f458a40ad66c81 100644
--- a/src/developer/debug/zxdb/console/command_utils.cc
+++ b/src/developer/debug/zxdb/console/command_utils.cc
@@ -330,15 +330,6 @@ const char* BreakpointEnabledToString(bool enabled) {
   return enabled ? "Enabled" : "Disabled";
 }
 
-const char* BreakpointTypeToString(debug_ipc::BreakpointType type) {
-  switch (type) {
-    case debug_ipc::BreakpointType::kSoftware:
-      return "Software";
-    case debug_ipc::BreakpointType::kHardware:
-      return "Hardware";
-  }
-}
-
 std::string DescribeJobContext(const ConsoleContext* context,
                                const JobContext* job_context) {
   int id = context->IdForJobContext(job_context);
diff --git a/src/developer/debug/zxdb/console/command_utils.h b/src/developer/debug/zxdb/console/command_utils.h
index ccd9886d89b2dd20ba1a609a6140ab32ab06fa68..d7dec3089cd48c161c426da1293d46c400796104 100644
--- a/src/developer/debug/zxdb/console/command_utils.h
+++ b/src/developer/debug/zxdb/console/command_utils.h
@@ -86,7 +86,6 @@ std::string BreakpointScopeToString(const ConsoleContext* context,
                                     const BreakpointSettings& settings);
 std::string BreakpointStopToString(BreakpointSettings::StopMode mode);
 const char* BreakpointEnabledToString(bool enabled);
-const char* BreakpointTypeToString(debug_ipc::BreakpointType);
 
 std::string DescribeTarget(const ConsoleContext* context, const Target* target);