Thanks @raytong, the geom_col trick is helpful for what I am doing. I also realized when looking over my examples that setting the breaks for a histogram layer does appear to fix the bins when adding new layers. So, if a user supplies a histogram plot without the breaks specified, you can set the breaks before adding new layers.
suppressMessages(library(dplyr))
library(tibble)
library(ggplot2)
dtf <- c(144.8531, 192.7375, 226.3156, 200.2969,
211.3438, 215.5562, 199.6437, 190.1531,
189.6469, 216.4906) %>%
enframe()
plot1 <- dtf %>%
ggplot() +
geom_histogram(aes(value), bins = 47)
plot1

### add breaks to plot1
breaks <- c(
layer_data(plot1, 1)$xmin,
layer_data(plot1, 1)$xmax
) %>%
unique() %>%
sort()
plot1$layers[[1]]$stat_params$breaks <- breaks
###
new_dtf <- c(145.2158, 189.4889, 189.4889, 193.0307,
200.1144, 200.1144, 210.7399, 216.0527,
216.0527, 226.6783) %>%
enframe()
plot2 <- plot1 +
geom_histogram(aes(value), data = new_dtf,
alpha = 0.1, fill = "red")
plot2
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

layer_data(plot1, 1) %>%
select(xmin, xmax) %>%
head()
#> xmin xmax
#> 1 144.3303 146.1012
#> 2 146.1012 147.8721
#> 3 147.8721 149.6431
#> 4 149.6431 151.4140
#> 5 151.4140 153.1849
#> 6 153.1849 153.1849
layer_data(plot2, 1) %>%
select(xmin, xmax) %>%
head()
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> xmin xmax
#> 1 144.3303 146.1012
#> 2 146.1012 147.8721
#> 3 147.8721 149.6431
#> 4 149.6431 151.4140
#> 5 151.4140 153.1849
#> 6 153.1849 153.1849
Created on 2019-11-15 by the reprex package (v0.3.0)